Repository navigation
Description
Overview
@rhayes777 filed five issues on 2026-05-23 while auditing released 2026.5.21.1
against the documented public API: PyAutoArray#332, PyAutoArray#333,
PyAutoGalaxy#440, PyAutoLens#531, PyAutoLens#532. They received zero replies for
66 days. All five were answered on 2026-07-28, and every one of the 16 findings
was re-verified against current main first — all 16 still reproduce.
This epic tracks the campaign that fixes them. It exists because all five replies
promise @rhayes777 a single place to watch.
Decision (2026-07-28): we implement in-house. His "Happy to PR if useful" offer
was declined warmly — the affected constructors sit on JAX-traced hot paths and
guards that stay correct under tracing are not a fair hand-off.
Verified against main
PyAutoArray@616e8b4c · PyAutoGalaxy@f0b65f39 · PyAutoLens@6567b3b1c — all clean,
zero ahead/behind.
| Issue | Findings | Verified |
|---|---|---|
| #332 | ConstantSplit×RectangularUniform; adaptive-mesh precondition error |
3/3 |
| #333 | B5, B6, B7, B8, B13 — input validation | 5/5 |
| PyAutoGalaxy#440 | B9, B10, B11, B12 — profile validation | 4/4 |
| PyAutoLens#531 | PointSolver AxisError + IndexError |
2/2 |
| PyAutoLens#532 | B4 + redshift ordering | 2/2 |
Correction to #332's headline
#332 reports that Delaunay and KNNBarycentric are "unusable in FitImaging".
They are not. They require an image-plane mesh grid via adapt_images, and with
it both fit cleanly:
Delaunay(pixels=100) + Constant + adapt_images -> log_evidence 5084.7513
KNNBarycentric(pixels=100) + Constant + adapt_images -> log_evidence 5211.7226
Delaunay(pixels=100) + Constant, NO adapt -> AttributeError 'NoneType'
RectangularUniform(15,15) + ConstantSplit -> AttributeError (Split unsupported)
RectangularAdaptDensity + ConstantSplit -> IndexError (Split unsupported)
Delaunay(pixels=100) + ConstantSplit + adapt -> log_evidence 5096.4420
The real defect is that a missing precondition surfaces as
AttributeError: 'NoneType' object has no attribute 'array' from inside
border_relocator.py, naming nothing the caller controls.
This inverts the fix direction. A regression test must assert that bare
construction fails clearly, naming adapt_images — not that it succeeds.
Phases
Phase 1 — genuine crash bugs (real user impact, no workaround) — #416, in progress
Splitregularization on rectangular meshes. Rectangular does not support
Split— the fix is a clear "unsupported" exception, not the missing capability.
Verified scope is 9 combinations in 2 failure modes (3 rectangular meshes x 3
Splitregularizations):RectangularUniform→AttributeError(property absent);
RectangularAdaptDensity/RectangularAdaptImage→IndexError(the pass-through
atrectangular.py:460claims split "reuses the same mappings", which crashes one
frame later inreg_split_from).Delaunay+ConstantSplitworks, so this is
specific to the rectangular family.PointSolver.solveon a source outside the caustic →numpy AxisErrorPointSolver.solvewith loosepixel_scale_precision→IndexError
(same source at 0.001 returns 4 images)
Phase 2 — constructor validation sweep (9 findings: B4–B13)
One shared _validate_* helper. Where it lives must be decided before writing
it — PyAutoArray is the natural floor, since Galaxy and Lens both depend on it —
or the three repos ship inconsistent messages.
Phase 3 — error legibility
adapt_images precondition fails fast and legibly; regression test asserts the
clear failure. Plus B10 (2.357e-06 Isothermal/IsothermalSph difference at the
degenerate point) pinned at an explicit tolerance — not chased to bit-identity.
Phase 4 — HELD, awaiting @rhayes777
z_lens > z_source should warn rather than raise (multi-plane genuinely supports
geometries that look wrong under two-plane naming); negative redshift can raise
outright. The #532 reply asks him whether even a warning would be noise in a real
multi-plane setup. Held until he answers — everything else is unblocked.
Constraint carried into every phase
These constructors are JAX-traced. Guards must stay correct under tracing and
cost nothing when traced — no Python if on values that may be tracers.
Sharpened finding on B13
constant.py:43 squares the coefficient, which is why log_evidence is identical
for +1.0 and -1.0. But regularization_weights_from (constant.py:127) returns
the raw un-squared value, so a negative coefficient does leak negative
regularization weights into every consumer of that method. Not inert.
Activity
fix: reject split regularization on rectangular meshes at construction (
Jammy2211 commentedon Jul 29, 2026
Status update — phase 1 merged (2026-07-28)
@rhayes777 — the first tranche of the audit is in
main. This is the tranche with realuser impact and no workaround: three documented public features that crashed on realistic
inputs.
Splitregularization on rectangular meshes now raises a clear "unsupported" exception at construction9411904dPointSolver.solvereturns the single image when the source is outside the caustic; raises a clear error namingpixel_scale_precisionwhen the precision is too coarse to resolve any image2a3f1a63Two notes on scope, both of which grew from evidence rather than from the reports:
ConstantSplit×RectangularUniformfailure you reported is 9 combinations in2 failure modes — 3 rectangular meshes × 3
Splitregularizations.RectangularUniformgave the
AttributeErroryou saw;RectangularAdaptDensityandRectangularAdaptImagegave an
IndexErrorinstead, via a pass-through inrectangular.pythat claimed split"reuses the same mappings". It does not. That pass-through was deleted.
Splitregularization by design, so the fix is theexplicit exception, not the missing capability.
Delaunay+ConstantSplitworks and iscovered as the control (
log_evidence 5096.4420).PyAutoLens#531is closed.PyAutoArray#416(the phase-1 tracker) is closed.Remaining
adapt_imagesprecondition error legibility + B10 tolerance regression testz_lens > z_sourcein multi-planePhase 4 is held on the open question already put to you in
PyAutoLens#532 —
whether a
z_lens > z_sourcewarning would be noise in a real multi-plane setup. No rush; thenegative-redshift half of that finding is not blocked on it and rides with phase 2.
This issue stays open until phases 2–3 land; #332, #333, PyAutoGalaxy#440 and #532 stay
open with it.
fix: reject invalid constructor inputs (#333 — B5-B8, B13) (#440)
fix: name `adapt_images` when an adaptive mesh has no image-plane grid (
Jammy2211 commentedon Aug 9, 2026
Campaign complete — closing
All 16 findings from @rhayes777's 2026-05-23 audit are addressed, all five of his issues are closed, and phase 4 shipped today.
PointSolverfailuresadapt_imagesprecondition legibility + B10 tolerancez_lens > z_sourceThe phase-2 helper-home question, settled
autoarray/validate.py—is_concrete_scalar,validate_positive_finite,validate_non_negative_finite,validate_pixel_scales,validate_shape_native,validate_radii_ordered. PyAutoGalaxy and PyAutoLens import it; PyAutoGalaxy adds only per-parameter explanations. One message shape for one class of mistake across all three repos, which was the stated risk.Guards are tracer-safe by a single gate (
is_concrete_scalar), verified against real JAX 0.11.0 — construction underjax.jitworks andjax.gradflows through, while concrete bad values are still rejected.Phase 4 — resolved without the answer we asked for
@rhayes777 was asked on PyAutoLens#532 whether warning on
z_lens > z_sourcewould be noise in a real multi-plane setup, and did not reply. Rather than hold indefinitely, the warning ships behind its own filterable category (MultiPlaneRedshiftWarning), so a user for whom it is noise silences exactly that. It warns and never raises — multi-plane genuinely supports geometries that look inverted under two-plane naming.The noise question then answered itself empirically. A naive rule counting only
LightProfilefired in ~10 legitimate existing tests, taking the suite's warning count 18 → 44. Pixelized sources (which carry no light profile at all), point sources, and empty placeholder galaxies were all false positives. With those handled it fires in zero tests outside its own regression module, back to 18.Coverage went wider than reported in several places
Because guards went in at chokepoints rather than at the reported call sites:
Constant— and closed a real leak, sinceregularization_weights_fromreturns the coefficient unsquared whileregularization_matrix_fromsquares it.EllProfile, covering every elliptical light and mass profile.AbstractDatasetsubclass, not justImaging.elliptical_annular, which had the identical hole.One correction to the record
The Ell/Sph potential discrepancy reported in PyAutoGalaxy#566 and on PyAutoGalaxy#440 was overstated. It is not an accuracy defect: with over-sampling disabled the potential agrees to
3.2e-06, the same order as the deflections. The disagreement appears only under the defaultover_sample_size=4and is concentrated at the profile's singular centre, where it reaches ~7% locally — an over-sampling-at-a-cusp artefact. The benign ~1e-6 floor is the elliptical form clippingaxis_ratioto0.99999whileIsothermalSphhardcodes1.0, which is precisely B10 and is correctly pinned. Tracked separately; not part of this audit.Thanks again @rhayes777 — the audit found real bugs, and in two cases (B13's unsquared weights, and the
adapt_imageserror) the underlying problem was more substantial than the report suggested.Generated by Claude Code