Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 9 additions & 7 deletions dashboard.html

Large diffs are not rendered by default.

50 changes: 36 additions & 14 deletions dashboard.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ Every task the Mind is holding, on one page: what is in flight, what is parked,
| [In flight](#in-flight) (`active/`) | 2 |
| [Parked](#parked) (`parked.md`) | 3 |
| [Planned](#planned) (`planned.md`) | 6 |
| [Backlog](#backlog) (`draft/`) | 146 |
| [Backlog](#backlog) (`draft/`) | 148 |

## Start here

Expand Down Expand Up @@ -115,7 +115,13 @@ Every task the Mind is holding, on one page: what is in flight, what is parked,

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

- _(none right now)_
<details><summary>📋 <a href="draft/maintenance/libraries/defer_scipy_sparse_import.md">Defer the eager scipy.sparse import in derivative_util (~0.10 s of</a> — libraries · small · safe · normal</summary>

```
/start_dev draft/maintenance/libraries/defer_scipy_sparse_import.md
```

</details>

## In flight

Expand Down Expand Up @@ -229,7 +235,7 @@ Scoped but not started; some are not yet prompt files. Full detail in [`planned.

## Backlog

**146** filed prompts, not started. Each section is sorted most-pickable first (priority, then size). **23** of them belong to an epic and are listed only under [Epics](#epics) below.
**148** filed prompts, not started. Each section is sorted most-pickable first (priority, then size). **23** of them belong to an epic and are listed only under [Epics](#epics) below.

<details>
<summary><b>feature</b> — 28</summary>
Expand Down Expand Up @@ -730,7 +736,7 @@ Scoped but not started; some are not yet prompt files. Full detail in [`planned.
</details>

<details>
<summary><b>research</b> — 16</summary>
<summary><b>research</b> — 17</summary>

<details><summary>📋 <a href="draft/research/autoarray/delaunay_research.md">Deep research: Can we speed up Delaunay in PyAutoArray?</a> — autoarray · too-large · supervised · high</summary>

Expand Down Expand Up @@ -804,6 +810,14 @@ Scoped but not started; some are not yet prompt files. Full detail in [`planned.

</details>

<details><summary>📋 <a href="draft/research/libraries/intel_macos_support_policy.md">Is Intel macOS a supported platform, and what is the</a> — libraries · medium · supervised · normal</summary>

```
/start_dev draft/research/libraries/intel_macos_support_policy.md
```

</details>

<details><summary>📋 <a href="draft/research/pyautomemory/checkerboard_psf_mismatch_residual_diagnostic.md">Checkerboard PSF-mismatch residual diagnostic — research + document + ingest</a> — pyautomemory · medium · supervised · normal</summary>

```
Expand Down Expand Up @@ -863,7 +877,7 @@ Scoped but not started; some are not yet prompt files. Full detail in [`planned.
</details>

<details>
<summary><b>maintenance</b> — 18</summary>
<summary><b>maintenance</b> — 20</summary>

<details><summary>📋 <a href="draft/maintenance/ci/smoke_install_stale_jax_pin.md">smoke_install.sh's stale <code>jax&lt;0.7</code> pin — CI is on the right</a> — ci · low · supervised · medium</summary>

Expand All @@ -881,6 +895,14 @@ Scoped but not started; some are not yet prompt files. Full detail in [`planned.

</details>

<details><summary>📋 <a href="draft/maintenance/libraries/defer_scipy_sparse_import.md">Defer the eager scipy.sparse import in derivative_util (~0.10 s of</a> — libraries · small · safe · normal</summary>

```
/start_dev draft/maintenance/libraries/defer_scipy_sparse_import.md
```

</details>

<details><summary>📋 <a href="draft/maintenance/workspaces/config_key_mirror_drift.md">Mirror drifted library config keys into the workspace configs</a> — workspaces · small · supervised · normal</summary>

```
Expand Down Expand Up @@ -969,6 +991,14 @@ Scoped but not started; some are not yet prompt files. Full detail in [`planned.

</details>

<details><summary>📋 <a href="draft/maintenance/libraries/remove_pynufft_legacy_transformer.md">Remove pynufft + legacy TransformerNUFFTPyNUFFT</a> — libraries · low-medium · supervised · normal</summary>

```
/start_dev draft/maintenance/libraries/remove_pynufft_legacy_transformer.md
```

</details>

<details><summary>📋 <a href="draft/maintenance/autolens_profiling/jwst_lw_untracked_gitignore_gap.md">dataset/imaging/jwst_lw is untracked because the gitignore was never extended for</a> — autolens_profiling · small · supervised · low</summary>

```
Expand Down Expand Up @@ -1129,7 +1159,7 @@ Scoped but not started; some are not yet prompt files. Full detail in [`planned.
</details>

<details>
<summary><b>refactor</b> — 6</summary>
<summary><b>refactor</b> — 5</summary>

<details><summary>📋 <a href="draft/refactor/autogalaxy/einstein_radius_jit_native_seed_finder.md"><code>einstein_radius_jit_from</code>: replace static init_guess with a JAX-native seed finder</a> — autogalaxy · too-large · supervised · high</summary>

Expand Down Expand Up @@ -1163,14 +1193,6 @@ Scoped but not started; some are not yet prompt files. Full detail in [`planned.

</details>

<details><summary>📋 <a href="draft/refactor/autoarray/remove_pynufft_legacy_transformer.md">Remove pynufft + legacy TransformerNUFFTPyNUFFT (0.23s of import, one fallback</a> — autoarray · low-medium · supervised · normal</summary>

```
/start_dev draft/refactor/autoarray/remove_pynufft_legacy_transformer.md
```

</details>

<details><summary>📋 <a href="draft/refactor/pyautomind/repos_sync_check_dedup.md">Deduplicate repos_sync.py's check/write pairs</a> — pyautomind · medium · safe · low</summary>

```
Expand Down
19 changes: 18 additions & 1 deletion draft/bug/autoarray/pynufft_scipy_pinv2_dev_extra.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ Repos:
Difficulty: small
Autonomy: supervised
Priority: normal
Status: draft
Status: superseded

## Original request

Expand Down Expand Up @@ -40,3 +40,20 @@ exists, or retire the legacy backend and its tests. Keep this separate from the
- The PyNUFFT test either passes against the supported dependency set or is
removed together with an explicit backend-retirement decision.
- The standard optional-profile suite remains green.

## Superseded 2026-08-22

Resolved by `draft/maintenance/libraries/remove_pynufft_legacy_transformer.md`,
which takes this prompt's third sanctioned remedy — "retire the legacy backend
and its tests". `pynufft` is gone from PyAutoArray's `optional` and `dev`
extras, so there is no longer a dev-extra install that can hit
`scipy.linalg.pinv2`.

Confirmed on a clean Python 3.13 install (2026-08-22): with
`pynufft==2022.2.2` present, `hasattr(scipy.linalg, "pinv2")` is `False` under
SciPy 1.17.1 — the drift this prompt reported is real, and pre-existing rather
than a Python-floor regression as it said. pynufft 2022.2.2 also emits
`SyntaxWarning: "is" with 'str' literal` on 3.13, i.e. it is unmaintained
against the supported interpreter range.

Close this out when the removal PRs merge.
89 changes: 89 additions & 0 deletions draft/maintenance/libraries/defer_scipy_sparse_import.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
# Defer the eager scipy.sparse import in derivative_util (~0.10 s of import)

Type: maintenance
Target: libraries
Repos:
- @PyAutoArray
Difficulty: small
Autonomy: safe
Priority: normal
Status: in-flight

## Where this came from

Found 2026-08-22 while measuring the pynufft removal
(`draft/maintenance/libraries/remove_pynufft_legacy_transformer.md`). That task
assumed removing pynufft would take ~0.23 s off `import autoarray`. It takes
~10 ms. The reason is the real target:

`autoarray/operators/derivative_util.py:30` does

```python
from scipy.sparse import csr_matrix
```

at module scope. `scipy.sparse` costs **0.106 s cumulative** and is imported on
every `import autoarray`, whether or not anything touches a derivative
operator. pynufft's apparent 0.19 s was ~95 % this same shared subtree —
removing pynufft did not remove it, because `derivative_util` pulls it in
anyway.

## Evidence (Python 3.13, dev extras, median of 7 runs)

| | `import autoarray` |
|---|---|
| main, pynufft installed | 369.8 ms |
| pynufft removed | 359.9 ms |

`python -X importtime` on the pynufft-removed branch still shows
`scipy.sparse` at 0.106 s cumulative.

## Task

Defer the `csr_matrix` import into the functions that build the sparse
operators (the same pattern `transformer.py` already uses for `nufftax` via
`_load_nufftax()`). Check for other eager `scipy.sparse` importers before
assuming this is the only one — the win only lands if *no* module-scope import
of it survives on the `import autoarray` path.

Note the precedent in `transformer.py`: the deferral must survive unpickling in
multiprocessing workers, so hang it off the call sites rather than `__init__`
alone.

## Acceptance

- `python -X importtime -c "import autoarray" | grep scipy.sparse` is empty.
- Median `import autoarray` drops by ~0.10 s against the same measurement
method above (record the before/after numbers in the PR).
- Full suite green; sparse-operator behaviour unchanged.

## Correction + result (implemented 2026-08-22, PyAutoArray#477)

**This prompt's own premise was wrong, in exactly the way the pynufft one
was.** Deferring `derivative_util.py:30` changed nothing: `scipy.sparse` was
never imported from there. Traced with a `sys.meta_path` hook:

```
autoarray/__init__.py:80
-> inversion/mesh/mesh_geometry/delaunay.py:2 import scipy.spatial
-> scipy/spatial/__init__.py:111 from ._kdtree import *
-> scipy/spatial/_kdtree.py:4 from ._ckdtree import cKDTree
```

`scipy.spatial` (134 ms) pulls `scipy.sparse` (154 ms) transitively, so the
`csr_matrix` import was riding on a subtree already paid for. Deferring
`scipy.spatial` as well is what removes both — and is required to satisfy this
prompt's own acceptance criterion.

The general lesson, now hit twice: **a module's `importtime` cumulative figure
is not its exclusive cost.** Attributing a saving to a dependency requires
checking who else pulls its subtree in.

Result: `import autoarray` **464.4 ms -> 183.7 ms** (medians of 15 runs,
Python 3.13, dev extras) — a 281 ms saving, ~2.8x this prompt's ~0.10 s
estimate, because `scipy.spatial`'s own cost comes off too. Both greps are
empty. Suites green: autoarray 1179, autogalaxy 1103/1 skipped,
autolens 532/1 skipped.

Note `delaunay.py` already had local `import scipy.spatial` at two of its three
use sites — this deferral had been started and left half-done.
138 changes: 138 additions & 0 deletions draft/maintenance/libraries/remove_pynufft_legacy_transformer.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
# Remove pynufft + legacy TransformerNUFFTPyNUFFT

Type: maintenance
Target: libraries
Repos:
- @PyAutoArray
- @PyAutoGalaxy
- @PyAutoLens
Difficulty: low-medium
Autonomy: supervised
Priority: normal
Status: shipped

Re-homed 2026-08-22 from `draft/refactor/autoarray/`. The Brain Refactor Agent
refused it there (`SUSPECT-API-CHANGE`, effective autonomy `human-required`):
deleting a public class is not behaviour-preserving, so it cannot be a
`refactor/`. `maintenance/` ("dependency updates, hygiene, cleanup") is the
taxonomy fit for removing a dependency.

## Original request (verbatim, 2026-08-19)

> do we even use pynufft? maybe we should file a follow up to remove it I think
> its purely for one function, so make that filing remove it but also include
> this check of import time.

## Corrections to the original filing (measured 2026-08-22)

The 2026-08-19 filing had two factual errors, both found during implementation:

1. **pynufft was never a base dependency.** It sat in the `optional` extra
(`PyAutoArray/pyproject.toml:67`) and the `dev` extra (line 77). A plain
`pip install autoarray` never had it, so `TransformerNUFFTPyNUFFT` already
raised `pynufft_exception()` for most users.
2. **The import-time saving is ~10 ms, not ~230 ms.** Measured as the median of
7 runs on Python 3.13 with the dev extras: `import autoarray` goes
369.8 ms → 359.9 ms. `pynufft`'s 0.19 s *cumulative* import is ~95 %
`scipy.sparse` (0.11 s), which `autoarray/operators/derivative_util.py:30`
pulls in eagerly for `csr_matrix` regardless of pynufft. Only ~10 modules and
~10 ms are exclusive to pynufft.

The removal is still worth doing — an unmaintained dependency, one dead class,
and a `dev` extra that is broken against SciPy >= 1.17 — but **not** on
import-time grounds. The real 0.10 s win is filed separately as
`draft/maintenance/libraries/defer_scipy_sparse_import.md`.

## The Intel-macOS decision (settled 2026-08-22)

The original filing flagged one blocking question: does removing the pynufft
fallback cost Intel-Mac users their interferometer transformer? Verified
against PyPI:

- `jaxlib`'s **last Intel-macOS (x86_64) wheel is 0.4.38**, uploaded
2024-12-17. Every release since (through 0.11.1) is `macosx_11_0_arm64` only.
- `jaxlib` has **never published an sdist**, for any version — so there is no
pip fallback that builds from source.
- PyAutoNerves' floor is `jax>=0.7.0`
(`PyAutoNerves/pyproject.toml:38`, markered
`sys_platform != "darwin" or platform_machine == "arm64"`).
- `nufftax` is pure-JAX; even its `xp=np` path calls `nufftax.nufft2d2`. So no
JAX means no `TransformerNUFFT` either.

So Intel macOS keeps **`TransformerDFT` only** for interferometry — exact, pure
numpy, but O(N_vis x N_pix). Human decision (2026-08-22): accept this; record
it as a release-note line, not a blocker. The broader "is Intel macOS a
supported platform" question is filed as
`draft/research/libraries/intel_macos_support_policy.md`.

## Work done (branches pushed 2026-08-22)

All three on `claude/remove-pynufft-6uwt2z`:

- **@PyAutoArray** — deleted `TransformerNUFFTPyNUFFT`, the `NUFFTPlaceholder`
/ `NUFFT_cpu` module-scope try-import and `pynufft_exception()`; dropped the
re-exports from `__init__.py` and `type.py` and its arm of the `Transformer`
union; removed the three `test__nufft_pynufft__*` tests and the `"pynufft"`
arm of the nufftax-absent skip filter in `conftest.py`; dropped `pynufft`
from `optional` and the `pynufft==2022.2.2` pin from `dev`. Rewrote
`nufftax_exception()` and the `use_adjoint_scaling` docstrings, which cited
the deleted class. **1164 passed, 1 skipped.**
- **@PyAutoGalaxy** — dropped the `__init__.py:29` re-export and the `optional`
entry; updated installation docs, the feature overview and the live citation
surface (`files/citations.{md,tex,bib}`, `docs/index.md`) to cite `nufftax`.
**1103 passed, 1 skipped.**
- **@PyAutoLens** — same, minus the citation *addition* (nufftax was already
cited); the PyNUFFT entry was simply dropped. **532 passed, 1 skipped.**

`paper/` in both downstream repos was deliberately left untouched — published
JOSS records of what the software used at time of publication, not live docs.

## Remaining

1. **Workspace tier** (not started, needs the workspace repos):
- `autolens_workspace_test/scripts/interferometer/nufft.py:211` — the one
executable use; drop or replace the PyNUFFT leg of the parity comparison.
- Four prose mentions in autolens_workspace (`start_here.py`, `using_jax.py`,
`simulator.py`, `linear_light_profiles/modeling.py`) describing it as a
"non-JAX fallback".
- Check `PyAutoHands/autohands/config/no_run.yaml` per the ship_library
reference.
2. **PR bodies need the `## API Changes` breaking entry** (release-notes
contract): `TransformerNUFFTPyNUFFT` removed; migration is `TransformerNUFFT`
(nufftax), or `TransformerDFT` where JAX is unavailable.
3. All three library PRs **must merge together** — the downstream re-exports
break at import the moment PyAutoArray's removal lands alone.
4. Closes the separate bug draft
`draft/bug/autoarray/pynufft_scipy_pinv2_dev_extra.md`: the
`pynufft==2022.2.2` dev pin calls `scipy.linalg.pinv2`, absent from SciPy
1.17.1 (confirmed 2026-08-22 — `hasattr(scipy.linalg, "pinv2")` is `False`).
Retiring the backend was one of that prompt's three sanctioned remedies.

## Shipped 2026-08-22

Library tier merged: @PyAutoArray#475, @PyAutoGalaxy#583, @PyAutoLens#709 —
all green on CI, including each repo's `unittest-nojax` job, which is the
standing evidence that the no-JAX path survives without the pynufft fallback.
Merged galaxy -> lens -> array so main was never red (dropping a re-export is
safe against an autoarray that still has the class; the reverse is not).

Workspace tier raised: @autolens_workspace#497 (prose across `scripts/`,
`notebooks/`, `markdown/`) and @autolens_workspace_test#261 (the `nufft.py`
parity script rewritten around `TransformerDFT` as its sole reference; verified
by running it — all four tests pass, 3.0e-14 relative residual at 256x256).

`PyAutoHands/autohands/config/no_run.yaml` checked: no nufft entries, nothing
hidden there.

Two things found along the way that are NOT closed by this task:

1. `use_adjoint_scaling` is now a **no-op on both remaining transformers** — it
was load-bearing only for the deleted class's pynufft-internal IFFT
normalisation. Kept, with docstrings rewritten, rather than widening this
removal. Worth a separate decision.
2. `autolens_workspace_test/scripts/interferometer/jax_likelihood/rectangular_sparse.py`
recorded the `apply_sparse_operator` / `TransformerNUFFT` incompatibility as
being caused by pynufft's kernel-deconvolved adjoint scale. That backend is
gone; whether the incompatibility still holds against the nufftax adjoint is
**unverified**. The dead attribution was removed without asserting a
replacement claim.
Loading
Loading