Overview
Phase 8 of the euclid-dr1-prep epic (was 6c; renumbered in the 2026-09-01 Cortex split). The Delaunay source model's magnification has never been validated and the epic's owner suspects the pixel areas. This is a source-code audit of every Delaunay area/magnification path in PyAutoArray, with known-answer tests landed regardless of outcome. It is the software half of the question; the empirical half is Cortex phase 7 (PyAutoCortex/phases/euclid/magnification_robustness.md), which this audit must brief. Any real defect is filed as a separate bug prompt — this task does not grow into the fix.
Plan
- Map every Delaunay area/magnification code path — Voronoi cell areas behind
areas_for_magnification, barycentric dual areas behind the split-point weights, the tripcolor plotting path, the workspace source_science.py consumer, and the Euclid pipeline's magnification latent — and state what each computes.
- Prove or drop each suspicion with known-answer tests (analytic lattices, convex-hull totals, exact integrals of a linear field), not resemblance.
- Land the missing direct tests for
areas_for_magnification and barycentric_dual_area_from, and correct the areas_for_magnification docstring to what is actually zeroed.
- Check whether the Euclid pipeline's
magnification latent survives a Delaunay vis_pix / full_model stage at all.
- Write the verdict here and in the epic ledger, with an explicit statement for Cortex phase 7: are Delaunay magnification numbers trustworthy, and which area must they use?
- Any proven defect → separate
draft/bug/autoarray/ prompt with the reproduced failing case.
Detailed implementation plan
Affected Repositories
- PyAutoArray (primary — tests + docstring)
- PyAutoLens (read-only:
autolens/analysis/latent.py::magnification reachability check; no edits unless a defect is found, then a separate prompt)
Branch Survey
| Repository |
Current Branch |
Dirty? |
| ./PyAutoArray |
main |
clean |
| ./PyAutoLens |
main |
clean |
Suggested branch: feature/delaunay-area-magnification-audit
What the pre-plan survey established
- Two different "areas" exist for a Delaunay mesh on two different paths:
MeshGeometryDelaunay.areas_for_magnification (autoarray/inversion/mesh/mesh_geometry/delaunay.py:195) = voronoi_areas_numpy (shoelace over scipy Voronoi cells). Only unbounded cells are marked -1 and zeroed; bounded-but-huge boundary cells are kept (the existing test__voronoi_areas_via_delaunay_from shows index 3 = 29.8 kept, index 4 = −1). The docstring says boundary pixels are zeroed — it overstates.
barycentric_dual_area_from (autoarray/inversion/mesh/interpolator/delaunay.py:342, plus an in-graph JAX scatter-add copy at ~:309) = Σ(triangle area / 3) per vertex; used only to weight split-regularisation points via areas_factor * sqrt(areas). Not used for flux or magnification.
- Plotting (
autoarray/plot/inversion.py::_plot_delaunay) uses tripcolor Gouraud — linear interpolation over triangles, whose integral is the barycentric dual area, not the Voronoi cell. Picture and number come from different geometry.
areas_for_magnification has zero library callers; it serves only the four pixelized source_science.py workspace scripts (Σ reconstruction × mesh_areas as source-plane flux). Those scripts are what Cortex phase 7's Delaunay leg would use.
- The Euclid pipeline's magnification latent (
autolens/analysis/latent.py::magnification) is a flux ratio via galaxies[-1].image_2d_from(...) and never touches areas_for_magnification. Whether it is finite for a Pixelization source galaxy is unverified.
sqrt is not on the magnification path; the known NaN-gradient hazard is confined to the interpolator's split-point weights.
- The cluster-epic prompt
draft/test/workspaces/mesh_magnification_correctness.md owns the library-level magnification API, non-Delaunay meshes and the simulate-and-recover campaign. This task stays Delaunay-only.
Implementation Steps
test_autoarray/inversion/pixelization/mesh_geometry/test_delaunay.py — add:
test__areas_for_magnification__uniform_lattice: n×n unit lattice → every interior Voronoi cell area == 1.0; every hull point unbounded → 0.0; Σ == (n−2)². Pins the real semantics.
test__areas_for_magnification__bounded_boundary_cells_are_kept: the existing 6-point configuration → index 3 (≈29.8) is kept, only index 4 zeroed — documents the bias candidate explicitly.
test__areas_for_magnification__repeat_calls_agree: two calls agree; the -1 sentinel is not written back into any cached state.
test_autoarray/inversion/mesh/interpolator/test_delaunay.py (create if absent, mirroring the existing interpolator test layout) — add:
test__barycentric_dual_area__single_triangle: each vertex == A/3.
test__barycentric_dual_area__sums_to_convex_hull_area: random points → Σ dual == scipy.spatial.ConvexHull(points).volume; assert Σ areas_for_magnification differs for the same points (records the divergence).
test__linear_field_integral__dual_areas_exact: f = a + b·y + c·x at the vertices; exact integral over the hull equals Σ f_i·dual_i to rounding; Σ f_i·voronoi_i differs on a non-uniform mesh.
- NumPy vs JAX parity:
barycentric_dual_area_from(xp=np) equals the in-graph scatter-add on the same padded simplices.
autoarray/inversion/mesh/mesh_geometry/delaunay.py — rewrite the areas_for_magnification docstring to the proven semantics (unbounded cells → 0; bounded boundary cells kept; these are Voronoi cells, not the interpolant's dual areas). No behavioural change.
- Audit evidence (scratch script, numbers reported here, not shipped): a Gaussian source strictly inside the hull of a Delaunay mesh; compare Σ reconstruction·voronoi areas, Σ reconstruction·dual areas, and the mapped-reconstruction image-plane flux against the analytic source flux. Report which denominator recovers μ and the sign/size of the boundary effect.
- Euclid reachability (read-only): look for
magnification in the latent outputs of the vis_pix / full_model stages under euclid_strong_lens_modeling_pipeline/output/ral_*; if absent (NaN latents are dropped from latent_summary.json), confirm by evaluating the latent on a stored Delaunay fit in test mode. Outcome is a finding.
- If a defect is proven (expected candidate: the magnification denominator should integrate the interpolant with barycentric dual areas, or bounded boundary cells bias the Voronoi sum), file
draft/bug/autoarray/<name>.md via /intake with the reproduced case and Epic: euclid-dr1-prep; cross-link from the ledger and here. Do not fix in this PR.
- Write the per-path audit table (path, what it computes, verdict, evidence) and the Cortex-phase-7 statement into this issue and the epic ledger.
Key Files
autoarray/inversion/mesh/mesh_geometry/delaunay.py — voronoi_areas_numpy, voronoi_areas, areas_for_magnification
autoarray/inversion/mesh/interpolator/delaunay.py — barycentric_dual_area_from, in-graph dual areas, split-point weights
autoarray/plot/inversion.py — _plot_delaunay
test_autoarray/inversion/pixelization/mesh_geometry/test_delaunay.py — existing test__voronoi_areas_via_delaunay_from
autolens_workspace/scripts/imaging/features/pixelization/source_science.py — the only consumer of areas_for_magnification
PyAutoLens/autolens/analysis/latent.py — magnification, total_source_flux
Verification
pytest test_autoarray/inversion/pixelization/mesh_geometry/test_delaunay.py test_autoarray/inversion/mesh -q green in the worktree; full pytest test_autoarray -q before the PR.
- Every Delaunay area path either matched to an analytic answer in a landed test or flagged with a reproduced failing case here.
Original Prompt
Click to expand starting prompt
Audit the Delaunay pixel-area and magnification source code for correctness bugs
Type: bug
Target: autoarray
Repos:
- PyAutoArray
- PyAutoLens
Themes:
- pixelization
- euclid
Difficulty: small-medium
Autonomy: supervised
Priority: normal
Status: formalised
Consequence: judge
Review-minutes: 25
Unattended: ready
Epic: euclid-dr1-prep
Phase: 8
Parent: draft/feature/euclid/euclid_dr1_prep_epic.md
Filed: 2026-08-28
Phase 8 of the Euclid DR1 preparation epic (was 6c; renumbered 2026-09-01 in the Cortex split,
where the old 6b became PyAutoCortex phases/euclid/magnification_robustness). Can run
alongside the magnification-robustness phase and does not gate on it — that phase is the
empirical half (does μ come out right on data?), this one is the
source-code half (does the code look right?). Either can find the defect first.
User request (verbatim, the follow-up clause of 6b):
"""
We have also never really validated or tested the magnifcitations using
the Delaunay source model, and this could even have bugs (E.g due to pixel areas not being quite right). So, for this
Euclid epic do all of the magnification comparisons you can on the 10 lenses in this spirit, but also have a follow up issue
which checks if the soruce code itself looks like it might have a bug or issue with the Delaunay area and thus magnification calculations.
"""
Where to look
PyAutoArray mesh geometry: the Delaunay areas_for_magnification implementation
(voronoi_areas, with boundary cells zeroed via a -1 sentinel) and its
rectangular-adaptive sibling. The cluster epic's audit
(draft/test/workspaces/mesh_magnification_correctness.md) already established that
areas_for_magnification exists for only two mesh geometries, has zero library
callers (it serves only workspace scripts), and has no direct test — only its
delegates are tested. That is exactly the shape a latent bug hides in.
- The boundary-cell semantics. Zeroing boundary cells changes the summed source-plane
area and therefore μ directly. Is the zeroing correct, or does it bias μ high?
PyAutoArray/autoarray/plot/inversion.py::_plot_delaunay and the Delaunay mapper —
check whether the areas used for plotting and the areas used for magnification
come from the same computation. Divergence there is a classic source of "the picture
looks right but the number is wrong".
- The interaction with
sqrt on dual areas — there is a known NaN hazard in the Delaunay
dual-area gradient path; check whether the same expression is on the magnification
path.
Method
This is an audit, not a rewrite. Read the code, then prove each suspicion or drop it:
- Construct known-answer configurations (a uniform triangulation of known total area,
a mesh with an analytically computable source-plane area) and check the code returns
the analytic value. A resemblance verdict is not verification.
- Where a suspected bug is found, reproduce it in a minimal test before proposing a
fix, and check whether it is reachable from the paths Euclid actually uses.
- Do not exempt a case because it "looks intentional" — if boundary zeroing is
deliberate, find the commit or comment that says so.
Deliverables
- A written audit: each area/magnification code path, what it computes, and whether it
is correct.
- Known-answer tests for Delaunay
areas_for_magnification (the missing direct test),
landed regardless of whether a bug is found — the absence of a test is itself the
defect the cluster-epic audit flagged.
- If a real defect is found: file a separate bug prompt for the fix rather than
growing this one, and tell phase 6b immediately so its Delaunay leg is interpreted
correctly.
Acceptance / gate
- Every Delaunay area/magnification path either verified against an analytic answer or
flagged with a reproduced failing case.
- Direct tests exist where there were none.
- A clear statement to 6b: are its Delaunay magnification numbers trustworthy?
Overview
Phase 8 of the
euclid-dr1-prepepic (was 6c; renumbered in the 2026-09-01 Cortex split). The Delaunay source model's magnification has never been validated and the epic's owner suspects the pixel areas. This is a source-code audit of every Delaunay area/magnification path in PyAutoArray, with known-answer tests landed regardless of outcome. It is the software half of the question; the empirical half is Cortex phase 7 (PyAutoCortex/phases/euclid/magnification_robustness.md), which this audit must brief. Any real defect is filed as a separate bug prompt — this task does not grow into the fix.Plan
areas_for_magnification, barycentric dual areas behind the split-point weights, thetripcolorplotting path, the workspacesource_science.pyconsumer, and the Euclid pipeline'smagnificationlatent — and state what each computes.areas_for_magnificationandbarycentric_dual_area_from, and correct theareas_for_magnificationdocstring to what is actually zeroed.magnificationlatent survives a Delaunayvis_pix/full_modelstage at all.draft/bug/autoarray/prompt with the reproduced failing case.Detailed implementation plan
Affected Repositories
autolens/analysis/latent.py::magnificationreachability check; no edits unless a defect is found, then a separate prompt)Branch Survey
Suggested branch:
feature/delaunay-area-magnification-auditWhat the pre-plan survey established
MeshGeometryDelaunay.areas_for_magnification(autoarray/inversion/mesh/mesh_geometry/delaunay.py:195) =voronoi_areas_numpy(shoelace over scipy Voronoi cells). Only unbounded cells are marked-1and zeroed; bounded-but-huge boundary cells are kept (the existingtest__voronoi_areas_via_delaunay_fromshows index 3 = 29.8 kept, index 4 = −1). The docstring says boundary pixels are zeroed — it overstates.barycentric_dual_area_from(autoarray/inversion/mesh/interpolator/delaunay.py:342, plus an in-graph JAX scatter-add copy at ~:309) = Σ(triangle area / 3) per vertex; used only to weight split-regularisation points viaareas_factor * sqrt(areas). Not used for flux or magnification.autoarray/plot/inversion.py::_plot_delaunay) usestripcolorGouraud — linear interpolation over triangles, whose integral is the barycentric dual area, not the Voronoi cell. Picture and number come from different geometry.areas_for_magnificationhas zero library callers; it serves only the four pixelizedsource_science.pyworkspace scripts (Σ reconstruction × mesh_areasas source-plane flux). Those scripts are what Cortex phase 7's Delaunay leg would use.autolens/analysis/latent.py::magnification) is a flux ratio viagalaxies[-1].image_2d_from(...)and never touchesareas_for_magnification. Whether it is finite for aPixelizationsource galaxy is unverified.sqrtis not on the magnification path; the known NaN-gradient hazard is confined to the interpolator's split-point weights.draft/test/workspaces/mesh_magnification_correctness.mdowns the library-level magnification API, non-Delaunay meshes and the simulate-and-recover campaign. This task stays Delaunay-only.Implementation Steps
test_autoarray/inversion/pixelization/mesh_geometry/test_delaunay.py— add:test__areas_for_magnification__uniform_lattice: n×n unit lattice → every interior Voronoi cell area == 1.0; every hull point unbounded → 0.0; Σ == (n−2)². Pins the real semantics.test__areas_for_magnification__bounded_boundary_cells_are_kept: the existing 6-point configuration → index 3 (≈29.8) is kept, only index 4 zeroed — documents the bias candidate explicitly.test__areas_for_magnification__repeat_calls_agree: two calls agree; the-1sentinel is not written back into any cached state.test_autoarray/inversion/mesh/interpolator/test_delaunay.py(create if absent, mirroring the existing interpolator test layout) — add:test__barycentric_dual_area__single_triangle: each vertex == A/3.test__barycentric_dual_area__sums_to_convex_hull_area: random points → Σ dual ==scipy.spatial.ConvexHull(points).volume; assert Σareas_for_magnificationdiffers for the same points (records the divergence).test__linear_field_integral__dual_areas_exact: f = a + b·y + c·x at the vertices; exact integral over the hull equals Σ f_i·dual_i to rounding; Σ f_i·voronoi_i differs on a non-uniform mesh.barycentric_dual_area_from(xp=np)equals the in-graph scatter-add on the same padded simplices.autoarray/inversion/mesh/mesh_geometry/delaunay.py— rewrite theareas_for_magnificationdocstring to the proven semantics (unbounded cells → 0; bounded boundary cells kept; these are Voronoi cells, not the interpolant's dual areas). No behavioural change.magnificationin the latent outputs of thevis_pix/full_modelstages undereuclid_strong_lens_modeling_pipeline/output/ral_*; if absent (NaN latents are dropped fromlatent_summary.json), confirm by evaluating the latent on a stored Delaunay fit in test mode. Outcome is a finding.draft/bug/autoarray/<name>.mdvia/intakewith the reproduced case andEpic: euclid-dr1-prep; cross-link from the ledger and here. Do not fix in this PR.Key Files
autoarray/inversion/mesh/mesh_geometry/delaunay.py—voronoi_areas_numpy,voronoi_areas,areas_for_magnificationautoarray/inversion/mesh/interpolator/delaunay.py—barycentric_dual_area_from, in-graph dual areas, split-point weightsautoarray/plot/inversion.py—_plot_delaunaytest_autoarray/inversion/pixelization/mesh_geometry/test_delaunay.py— existingtest__voronoi_areas_via_delaunay_fromautolens_workspace/scripts/imaging/features/pixelization/source_science.py— the only consumer ofareas_for_magnificationPyAutoLens/autolens/analysis/latent.py—magnification,total_source_fluxVerification
pytest test_autoarray/inversion/pixelization/mesh_geometry/test_delaunay.py test_autoarray/inversion/mesh -qgreen in the worktree; fullpytest test_autoarray -qbefore the PR.Original Prompt
Click to expand starting prompt
Audit the Delaunay pixel-area and magnification source code for correctness bugs
Type: bug
Target: autoarray
Repos:
Themes:
Difficulty: small-medium
Autonomy: supervised
Priority: normal
Status: formalised
Consequence: judge
Review-minutes: 25
Unattended: ready
Epic: euclid-dr1-prep
Phase: 8
Parent: draft/feature/euclid/euclid_dr1_prep_epic.md
Filed: 2026-08-28
Phase 8 of the Euclid DR1 preparation epic (was 6c; renumbered 2026-09-01 in the Cortex split,
where the old 6b became
PyAutoCortexphases/euclid/magnification_robustness). Can runalongside the magnification-robustness phase and does not gate on it — that phase is the
empirical half (does μ come out right on data?), this one is the
source-code half (does the code look right?). Either can find the defect first.
User request (verbatim, the follow-up clause of 6b):
"""
We have also never really validated or tested the magnifcitations using
the Delaunay source model, and this could even have bugs (E.g due to pixel areas not being quite right). So, for this
Euclid epic do all of the magnification comparisons you can on the 10 lenses in this spirit, but also have a follow up issue
which checks if the soruce code itself looks like it might have a bug or issue with the Delaunay area and thus magnification calculations.
"""
Where to look
PyAutoArraymesh geometry: the Delaunayareas_for_magnificationimplementation(
voronoi_areas, with boundary cells zeroed via a-1sentinel) and itsrectangular-adaptive sibling. The cluster epic's audit
(
draft/test/workspaces/mesh_magnification_correctness.md) already established thatareas_for_magnificationexists for only two mesh geometries, has zero librarycallers (it serves only workspace scripts), and has no direct test — only its
delegates are tested. That is exactly the shape a latent bug hides in.
area and therefore μ directly. Is the zeroing correct, or does it bias μ high?
PyAutoArray/autoarray/plot/inversion.py::_plot_delaunayand the Delaunay mapper —check whether the areas used for plotting and the areas used for magnification
come from the same computation. Divergence there is a classic source of "the picture
looks right but the number is wrong".
sqrton dual areas — there is a known NaN hazard in the Delaunaydual-area gradient path; check whether the same expression is on the magnification
path.
Method
This is an audit, not a rewrite. Read the code, then prove each suspicion or drop it:
a mesh with an analytically computable source-plane area) and check the code returns
the analytic value. A resemblance verdict is not verification.
fix, and check whether it is reachable from the paths Euclid actually uses.
deliberate, find the commit or comment that says so.
Deliverables
is correct.
areas_for_magnification(the missing direct test),landed regardless of whether a bug is found — the absence of a test is itself the
defect the cluster-epic audit flagged.
growing this one, and tell phase 6b immediately so its Delaunay leg is interpreted
correctly.
Acceptance / gate
flagged with a reproduced failing case.