Skip to content

Commit 34bcca2

Browse files
authored
mind: file autofit mock all-ones ell_comps bug from the workspace smoke triage (#183)
The 2026-08-10 Workspace Smoke ell_comps failures split three ways. Two are resolved: the sampler-draw legs by PyAutoGalaxy#568 (resample invalid profile parameters), and the one genuinely unphysical shipped literal, (0.5, 0.9) in HowToGalaxy tutorial_3_fitting, by HowToGalaxy#65. The remaining seven aggregator legs across the two *_workspace_test repos fail on ell_comps=(1.0, 1.0), which PyAutoGalaxy#568 does not help because the aggregator rebuilds instances outside any likelihood call. Narrowed to PyAutoFit's mock scaffolding, which fills every parameter with a blanket 1.0 — safe for most parameters, invalid for any ell_comps. The exact call site is not pinned; that needs a real autogalaxy environment. The prompt records the evidence, and records the plausible-but-disproven hypothesis (the scripts' own parameter_list_with_physical_ell_comps helper, reproduced against installed autofit and shown to work correctly) so it is not re-tread. Also regenerates dashboard.md (backlog 135 -> 136).
1 parent 535cb7a commit 34bcca2

2 files changed

Lines changed: 164 additions & 6 deletions

File tree

dashboard.md

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# PyAutoMind task dashboard
22

3-
<!-- generated by `pyauto-brain intake dashboard --apply` on 2026-08-11 — regenerate, do not hand-edit -->
3+
<!-- generated by `pyauto-brain intake dashboard --apply` on 2026-08-12 — regenerate, do not hand-edit -->
44

55
Every task the Mind is holding, on one page: what is in flight, what is parked, and the whole backlog to pick from. Pick a line, then run `/start_dev <prompt-path>` to start it.
66

@@ -11,16 +11,17 @@ Tasks only — the organism's health lives with the Heart (`/health`), not here.
1111
| [In flight](#in-flight) (`active/`) | 8 |
1212
| [Parked](#parked) (`parked.md`) | 6 |
1313
| [Planned](#planned) (`planned.md`) | 7 |
14-
| [Backlog](#backlog) (`draft/`) | 135 |
14+
| [Backlog](#backlog) (`draft/`) | 136 |
1515

1616
Live on GitHub: [open issues](https://github.com/search?q=org%3APyAutoLabs+is%3Aissue+is%3Aopen&type=issues) · [open pull requests](https://github.com/search?q=org%3APyAutoLabs+is%3Apr+is%3Aopen&type=prs)
1717

1818
## Start here
1919

20-
**Highest priority** (filed as `high`) — showing 12 of 30
20+
**Highest priority** (filed as `high`) — showing 12 of 31
2121

2222
- [pre_build stages untracked files, publishing uncommitted human work](draft/bug/pyautohands/pre_build_stages_untracked_wip.md) — pyautohands · small · supervised · high
2323
- [TRIAGE: needs manual review before routing](draft/triage/jax_zero_contour.md) — medium · safe · high
24+
- [PyAutoFit mock scaffolding fills every parameter with 1.0, which is](draft/bug/autofit/mock_all_ones_parameters_break_ell_comps_guard.md) — autofit · medium · supervised · high
2425
- [PyAutoLens RTD docs: three-regime restructure (multi_galaxy / group / cluster)](draft/docs/autolens/docs_three_regime_restructure.md) — autolens · medium · supervised · high
2526
- [Optimize pixelized Prodigy settings on the laptop GPU](draft/research/autolens_workspace_developer/pixelized_prodigy_laptop_gpu_phase_2_settings.md) — autolens_workspace_developer · medium · human-required · high
2627
- [Release does not sync __version__ stamps and workspace pins back](draft/bug/pyautobuild/release_version_sync_back_to_main.md) — pyautobuild · medium · supervised · high
@@ -30,7 +31,6 @@ Live on GitHub: [open issues](https://github.com/search?q=org%3APyAutoLabs+is%3A
3031
- [multi_galaxy package: new regime package in autolens_workspace](draft/docs/autolens/multi_galaxy_package.md) — autolens · large · supervised · high
3132
- [Tune the JAX multi-start optimizers into a standard option (MGE](draft/experiment/autolens_profiling/jax_optimizer_settings_tuning.md) — autolens_profiling · large · supervised · high
3233
- [Profile and speed up JAX likelihood-function compile times (all use](draft/feature/autolens_profiling/jax_compile_time_profiling.md) — autolens_profiling · large · supervised · high
33-
- [Optimize MultiStartProdigy for pixelized meshes on the laptop GPU](draft/research/autolens_workspace_developer/pixelized_prodigy_laptop_gpu.md) — autolens_workspace_developer · large · human-required · high
3434

3535
**Quick wins** (small enough, and safe enough to run unattended)
3636

@@ -95,12 +95,13 @@ Scoped but not started; some are not yet prompt files. Full detail in [`planned.
9595

9696
## Backlog
9797

98-
**135** filed prompts, not started. Each section is sorted most-pickable first (priority, then size).
98+
**136** filed prompts, not started. Each section is sorted most-pickable first (priority, then size).
9999

100100
<details>
101-
<summary><b>bug</b> — 39</summary>
101+
<summary><b>bug</b> — 40</summary>
102102

103103
- [pre_build stages untracked files, publishing uncommitted human work](draft/bug/pyautohands/pre_build_stages_untracked_wip.md) — pyautohands · small · supervised · high
104+
- [PyAutoFit mock scaffolding fills every parameter with 1.0, which is](draft/bug/autofit/mock_all_ones_parameters_break_ell_comps_guard.md) — autofit · medium · supervised · high
104105
- [Release does not sync __version__ stamps and workspace pins back](draft/bug/pyautobuild/release_version_sync_back_to_main.md) — pyautobuild · medium · supervised · high
105106
- [EP hierarchical parent-scale collapse: cure the basin, or document the](draft/bug/autofit/ep_scale_collapse_basin_cure_or_caveat.md) — autofit · too-large · human-required · high
106107
- [`NFWTruncatedSph.potential_2d_from`: MGE potential fails `grad(psi)=alpha` self-consistency](draft/bug/autogalaxy/nfw_truncated_potential_accuracy.md) — autogalaxy · too-large · supervised · high
Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
# PyAutoFit mock scaffolding fills every parameter with 1.0, which is now an invalid `ell_comps`
2+
3+
Type: bug
4+
Target: PyAutoFit
5+
Repos:
6+
- PyAutoFit
7+
- autogalaxy_workspace_test
8+
- autolens_workspace_test
9+
Difficulty: medium
10+
Autonomy: supervised
11+
Priority: high
12+
Status: formalised — NOT started. Root cause is narrowed to PyAutoFit's mock
13+
helpers but the exact call site is **not** pinned; see "What is not yet
14+
known". Requires an environment that can run the full autogalaxy stack.
15+
16+
## Symptom
17+
18+
Seven aggregator integration scripts across the two `*_workspace_test` repos fail
19+
with the same exception:
20+
21+
ValueError: ell_comps must satisfy ell_comps[0]**2 + ell_comps[1]**2 < 1;
22+
got (1.0, 1.0), whose magnitude is np.float64(1.4142135623730951)
23+
24+
Observed in PyAutoHeart Workspace Smoke run 31356506626 (2026-08-10), legs
25+
`autogalaxy_test / misc` and `autolens_test / misc`.
26+
27+
Failing scripts (all `scripts/misc/aggregator/`):
28+
29+
- `autogalaxy_workspace_test`: `ellipse.py`, `fit_imaging.py`,
30+
`fit_interferometer.py`, `galaxies.py`
31+
- `autolens_workspace_test`: `tracer.py`, `fit_imaging.py`,
32+
`fit_interferometer.py`
33+
34+
## Why this is a real bug and not a bad shipped value
35+
36+
The guard is correct and correctly placed. `validate_ell_comps` sits on
37+
`EllProfile`, the single base every elliptical profile inherits (`ag.Ellipse`
38+
included), and enforces `f = sqrt(e_y**2 + e_x**2) < 1` because the axis ratio is
39+
`q = (1 - f) / (1 + f)` — at `f >= 1` the ellipse degenerates to `q <= 0` and has
40+
no geometric meaning. `(1.0, 1.0)` gives `f = 1.414`, `q = -0.17`. Nothing should
41+
ever construct a profile with it.
42+
43+
This is **not** the same failure as the sampler-draw legs (`guides`, etc.), which
44+
were fixed by PyAutoGalaxy#568 making `ModelParameterException` a
45+
`FitException` so searches resample. That fix does not help here: the aggregator
46+
rebuilds instances from stored samples outside any likelihood call, so there is no
47+
resample path to take.
48+
49+
## Evidence
50+
51+
1. **The value is a hardcoded fill, not a sampled value.** It prints as plain
52+
`(1.0, 1.0)` — Python floats. The genuine sampler-draw failures in the same run
53+
print as `np.float64(-0.7446446619131553)`. Different provenance.
54+
55+
2. **Two places in PyAutoFit hardcode exactly this shape:**
56+
- `autofit/non_linear/mock/mock_samples.py``MockSamples.default_sample_list`
57+
builds `kwargs={path: 1.0 for path in self.model.paths}`.
58+
- `autofit/non_linear/mock/mock_samples_summary.py``MockSamplesSummary.__init__`
59+
sets `self._kwargs = {path: 1.0 for path in self.model.paths}`, which backs
60+
both `max_log_likelihood_sample` and `median_pdf_sample`.
61+
62+
A blanket `1.0` is a safe placeholder for most parameters and an invalid value
63+
for any `ell_comps`. `_make_samples` in `mock_search.py` already does the right
64+
thing (`prior.value_for(0.5)`), so the fix idiom exists in the same package.
65+
66+
3. **All 7 scripts construct `MockSearch` identically and never pass
67+
`samples_summary`:**
68+
69+
```python
70+
search = ag.m.MockSearch(
71+
samples=samples,
72+
result=af.m.MockResult(model=model, samples=samples,
73+
samples_summary=samples.summary()),
74+
)
75+
```
76+
77+
`MockSearch.__init__` therefore falls back to `MockSamplesSummary.default()`.
78+
Whether that asymmetry (a real model in `MockResult`, a default summary on the
79+
search) is the trigger or a red herring is the open question.
80+
81+
## Hypothesis already tested and DISPROVEN — do not re-tread
82+
83+
The obvious suspect is the helper copy-pasted into all 7 scripts:
84+
85+
```python
86+
def parameter_list_with_physical_ell_comps(value):
87+
parameter_list = model.prior_count * [value]
88+
for index, path_tuple in enumerate(model.all_paths):
89+
if "ell_comps" in path_tuple[0]:
90+
parameter_list[index] = 0.1
91+
return parameter_list
92+
```
93+
94+
It looks broken — `all_paths` returns a tuple of `Path`s per prior and
95+
`Path = Tuple[str, ...]`, so `path_tuple[0]` is a path tuple and `in` is
96+
exact-element membership, which would not match a leaf named `ell_comps_0`.
97+
98+
**It is not broken.** `ell_comps` has a tuple default, so PyAutoFit builds a
99+
`TuplePrior` attribute named `ell_comps`, and the path is
100+
`('ellipses', '0', 'ell_comps', 'ell_comps_0')` — it contains a bare `'ell_comps'`
101+
element, so the check matches. Reproduced by rebuilding `ellipse.py`'s exact model
102+
(two `Ellipse` models with fixed `major_axis`, plus the nested multipole
103+
collection) against installed autofit and running the real helper:
104+
105+
```
106+
[2] ('ellipses', '0', 'ell_comps', 'ell_comps_0') -> 0.1
107+
[3] ('ellipses', '0', 'ell_comps', 'ell_comps_1') -> 0.1
108+
ellipses[0].ell_comps = (0.1, 0.1)
109+
```
110+
111+
Index alignment is also fine: `all_paths` and `instance_from_vector`
112+
(`prior_tuples_ordered_by_id`) both order by prior id. **Changing this helper is a
113+
no-op — do not "fix" it.**
114+
115+
## What is not yet known
116+
117+
Which call site actually feeds the all-ones instance to the aggregator. Two
118+
candidates were checked and neither fits cleanly:
119+
120+
- `MockSamplesSummary.default()` uses an empty `Collection()`, so its `_kwargs`
121+
is `{}`, not a dict of 1.0s.
122+
- `MockSearch._fit_fast` evaluates at `[prior.mean for prior in
123+
model.priors_ordered_by_id]`, which is `0.0` for `ell_comps` — valid.
124+
125+
So the path runs through serialization into the database and back out through the
126+
aggregator, which is where it needs to be traced.
127+
128+
## Suggested approach
129+
130+
1. Run one failing script (`autogalaxy_workspace_test/scripts/misc/aggregator/ellipse.py`)
131+
against the full stack with a breakpoint or traceback on the guard, and record
132+
the actual construction stack. **This needs a real autogalaxy environment**
133+
it could not be done from a cloud session (autoarray/jax/numba would not
134+
install there).
135+
2. Fix at the PyAutoFit mock layer: replace the blanket `{path: 1.0 ...}` with
136+
prior-median values (`{path: prior.value_for(0.5) for path, prior in
137+
model.path_priors_tuples}`), matching `_make_samples`.
138+
3. Mind the blast radius: `MockSamples`, `MockSamplesSummary` and `MockSearch`
139+
have roughly 55 call sites inside PyAutoFit alone, plus the PyAutoGalaxy and
140+
PyAutoLens suites. Run all three suites, not just PyAutoFit's.
141+
4. Consider whether `MockSearch` should inherit the `samples_summary` from a
142+
passed-in `result` rather than silently defaulting.
143+
144+
## Notes
145+
146+
- Do not relax or move the `ell_comps` guard. It is correct.
147+
- Do not chase the `workspace-validation-report` artifact from a cloud session
148+
(blocked at the egress proxy). Per-job logs via the Actions API carry the same
149+
failures.
150+
- Sibling work already shipped: the one genuinely unphysical shipped literal,
151+
`ell_comps=(0.5, 0.9)` in HowToGalaxy `tutorial_3_fitting`, was corrected
152+
separately. An AST scan of 454 `ell_comps` literals across
153+
autogalaxy_workspace, autolens_workspace, HowToGalaxy, HowToLens and both
154+
`*_workspace_test` repos found no other violating literal, so this ticket is
155+
the whole remaining `ell_comps` surface.
156+
- PyAutoHeart#27 is a different family (release-profile timeouts and a JAX
157+
exception, 2026-07-06); it is not related.

0 commit comments

Comments
 (0)