diff --git a/REFERENCE.md b/REFERENCE.md index 64338c810..a846e5005 100644 --- a/REFERENCE.md +++ b/REFERENCE.md @@ -823,6 +823,15 @@ What blocks, and what does not: sides changed differently is the only conflict — takes `main`'s copy of the renders, and leaves `autonomy_log.md` to git's `merge=union` driver (`.gitattributes`; it is append-only). What that cannot settle blocks. +- **Branches the workflow never touches sync locally the same way.** A session + branch (`ccr-*` and the like) or a PR branch holding code must catch up with + `main` by hand, and its generated files conflict on almost every concurrent + push. `git fetch origin main && python3 scripts/ledger_merge.py sync` runs the + same merge: `--no-commit` merge of `origin/main`, `resolve`, then + `complete/index.md` and the dashboard re-rendered on the merged tree (the + Brain renderer from `$PYAUTO_BRAIN` or a sibling `PyAutoBrain`), staged for + you to commit. It refuses a dirty tree and stops, merge in progress, on + anything the grammar cannot settle. - **A blocked branch is written on an issue** titled ``ledger merge: `` needs a human`` (label `ledger-merge`), updated on every further attempt and closed by the run that finally lands it. A red run nobody is subscribed to diff --git a/complete/2026/11/bootstrap-test-root-skip.md b/complete/2026/11/bootstrap-test-root-skip.md new file mode 100644 index 000000000..cc38d68f0 --- /dev/null +++ b/complete/2026/11/bootstrap-test-root-skip.md @@ -0,0 +1,30 @@ +- summary: fixed in commit 748f8c0bb (this PR). `test_the_hook_survives_an_unwritable_tools_dir` probes `os.access(bin, W_OK)` after the chmod and skips with "cannot make a directory unwritable here (running as root?)" when root ignores the mode bits. As a normal user it still drives the failure path. +- witness: in this cloud container (root), `pytest tests/test_session_bootstrap.py -rs` reports 1 skipped with that reason. Mind suite 728 passed, 1 skipped. + +## Original prompt + +# `test_the_hook_survives_an_unwritable_tools_dir` fails when the suite runs as root + +Type: bug +Target: PyAutoMind +Repos: +- PyAutoMind +Themes: +- ci +Difficulty: small +Autonomy: safe +Priority: low +Status: formalised +Filed: 2026-11-05 +Consequence: glance +Witness: `pytest tests/test_session_bootstrap.py` reports the test as SKIPPED with a reason when run as root (cloud containers) and still drives the failure path as a normal user. +Review-minutes: 2 +Unattended: ready + +The test chmods a tool env's `bin/` to 0o500 to force `repair_uv_tools` down its "could not +repoint" path. Root ignores mode bits, so in a cloud session (tests run as root) the path is never +taken and the test fails on the environment, not on the code. Every Mind suite run in the +2026-11-05 queue session reported it as a known failure. Fix: probe `os.access(..., W_OK)` after +the chmod and skip with a reason when the directory is still writable. + + diff --git a/complete/2026/11/ledger-merge-sync.md b/complete/2026/11/ledger-merge-sync.md new file mode 100644 index 000000000..a161f33aa --- /dev/null +++ b/complete/2026/11/ledger-merge-sync.md @@ -0,0 +1,36 @@ +- summary: shipped in commit 748f8c0bb (this PR). `scripts/ledger_merge.py sync [--base origin/main] [--root]` / `sync_with_base()` does what `mind_ledger_merge.yml` does, for branches it never touches. It refuses a dirty tree; runs `git merge --no-commit --no-ff `; uses `resolve_conflicts` (registries merge by entry, renders conflict-free); stops as `blocked` with the merge in progress on anything the grammar cannot settle; otherwise re-renders `complete/index.md` (`lifecycle.py index --apply`) and the dashboard (the Brain renderer from `$PYAUTO_BRAIN` or a sibling/organs `PyAutoBrain`, else a NOT-regenerated note) on the merged tree; and stages them for the caller to commit. Documented in REFERENCE.md "How the ledger lands". +- witness: 3 new tests in tests/test_ledger_merge.py: ready + entry merge + injected re-render + MERGE_HEAD staged; up-to-date no-op and dirty-tree refusal; a non-ledger conflict blocked before rendering. 31 passed in that file. +- not done: extending the auto-merge workflow to `ccr-*` session branches. That is a policy decision for the human. + +## Original prompt + +# `ledger_merge.py sync`: bring a non-`claude/**` Mind branch up to date with main… + +Type: feature +Target: PyAutoMind +Repos: +- PyAutoMind +Themes: +- mind-workflow +Difficulty: small +Autonomy: supervised +Priority: medium +Status: formalised +Filed: 2026-11-05 +Consequence: judge +Witness: tests drive a fixture repo — a session branch behind main with entry-level registry changes on both sides and conflicting renders — through `sync_with_base`: status `ready`, registries merged by entry, renders regenerated on the merged tree by the (injected) renderer, merge left staged; `up-to-date` is a no-op; a dirty tree is refused; a non-ledger conflict stops as `blocked` before rendering. +Review-minutes: 5 +Unattended: ready + +`mind_ledger_merge.yml` settles concurrent-push conflicts for `claude/**`, `codex/**` and +`chatgpt/**` branches (`ledger_merge.py resolve`, then re-render). Session branches (`ccr-*`) and +PR branches holding code get none of that: PyAutoMind#539 needed three rounds of hand conflict +resolution on `dashboard.md` / `dashboard.html` / `state.json` / `complete/index.md` as other +sessions pushed to main every few minutes, and one round kept main's stale index because the +manual regen was a dry run (red `drift` check). A `.gitattributes` merge driver does not help: +GitHub ignores custom drivers. Add `ledger_merge.py sync [--base origin/main]` — merge with +`--no-commit`, `resolve`, re-render the generated files on the merged tree, stage, let the caller +commit — and document it beside the workflow in REFERENCE.md "How the ledger lands". +Extending the auto-merge workflow to `ccr-*` branches is a separate policy decision (not here). + + diff --git a/complete/2026/11/root-default-test-env-leak.md b/complete/2026/11/root-default-test-env-leak.md new file mode 100644 index 000000000..91437753c --- /dev/null +++ b/complete/2026/11/root-default-test-env-leak.md @@ -0,0 +1,30 @@ +- summary: fixed in commit 748f8c0bb (this PR). The module's autouse `forget_the_resolver` fixture now deletes `PYAUTO_ROOT` and `PYAUTO_ROOT_REASON` via monkeypatch. `test_an_explicit_override_is_never_second_guessed` still sets its own value. +- witness: `PYAUTO_ROOT=/home/user pytest tests/test_repos_sync_root_default.py` passes. The full suite gives 728 passed, 1 skipped, with and without the variable exported. + +## Original prompt + +# `test_repos_sync_root_default` inherits an exported `PYAUTO_ROOT` and fails + +Type: bug +Target: PyAutoMind +Repos: +- PyAutoMind +Themes: +- ci +Difficulty: small +Autonomy: safe +Priority: low +Status: formalised +Filed: 2026-11-05 +Consequence: glance +Witness: `PYAUTO_ROOT=/somewhere pytest tests/test_repos_sync_root_default.py` passes. +Review-minutes: 2 +Unattended: ready + +`workspace_root()` treats an exported `PYAUTO_ROOT` as "the operator's word" and never second- +guesses it, so `test_a_root_that_does_not_hold_this_checkout_is_refused` fails whenever the shell +running the suite has it exported — which the Brain CLI does for its children (observed +2026-11-05 after a `pyauto-brain intake` run in the same shell). Fix: the module's autouse fixture +clears `PYAUTO_ROOT` / `PYAUTO_ROOT_REASON` via monkeypatch; the override test sets its own. + + diff --git a/complete/index.md b/complete/index.md index e6f394503..470b49dcb 100644 --- a/complete/index.md +++ b/complete/index.md @@ -6,7 +6,7 @@ Token-light navigation over the finished-work records (schema: only then grep a dated bucket. Curators: edit the band between the CURATED markers; everything below GENERATED is rebuilt. -2172 records across 11 buckets. +2175 records across 11 buckets. ## Highlights @@ -136,6 +136,7 @@ markers; everything below GENERATED is rebuilt. - [autonomous-orchestrators-p4b](2026/11/autonomous-orchestrators-p4b.md) — phase 4b of 4a–4c; epic draft/feature/pyautobrain/autonomous_orchestrators_epic.md - [batch-watch-live-view](2026/11/batch-watch-live-view.md) — pilot 4c follow-up; issue PyAutoBrain#575 - [board-without-gh-phase2-legs](2026/11/board-without-gh-phase2-legs.md) — already shipped, closed as a stale draft. PyAutoBrain 15317af (merged via #564, 2026-11-03) "phase 2 — the rem… +- [bootstrap-test-root-skip](2026/11/bootstrap-test-root-skip.md) — fixed in commit 748f8c0bb (this PR). `test_the_hook_survives_an_unwritable_tools_dir` probes `os.access(bin, W… - [brain-hygiene-cleanup-bugs](2026/11/brain-hygiene-cleanup-bugs.md) - [chapter2-continuation](2026/11/chapter2-continuation.md) — All continuation scope merged: Tutorials 5 and 6, optional speed and runnable model_centred prior passing, sum… - [cloud-validation-rehearsal-clock-skew](2026/11/cloud-validation-rehearsal-clock-skew.md) @@ -168,6 +169,7 @@ markers; everything below GENERATED is rebuilt. - [intake-memory-line-organ-targets](2026/11/intake-memory-line-organ-targets.md) — already shipped — closed as stale draft. The `_with_memory` gate in `agents/conductors/intake/_intake.py` land… - [jax-joss-benchmark-repo](2026/11/jax-joss-benchmark-repo.md) — already shipped — PyAutoLabs/autolens_jax_joss: 9c66b020 (birth, 10 benchmark scripts), 64204f69 (A100 sweep o… - [latest-per-test-tie](2026/11/latest-per-test-tie.md) — test_autofit/results/test_identity.py::test_latest_per_keeps_the_latest_sibling flaked (main red at 963ff296a, +- [ledger-merge-sync](2026/11/ledger-merge-sync.md) — shipped in commit 748f8c0bb (this PR). `scripts/ledger_merge.py sync [--base origin/main] [--root]` / `sync_wi… - [lifecycle-p3-designation-proposals](2026/11/lifecycle-p3-designation-proposals.md) — decided and shipped — the human approved all 39 designations (datacube/delaunay gpu_a100 held provisional); Py… - [likelihood-lifecycle-p3-day-zero-pages](2026/11/likelihood-lifecycle-p3-day-zero-pages.md) - [likelihood-lifecycle-p3-day-zero-stamp](2026/11/likelihood-lifecycle-p3-day-zero-stamp.md) @@ -204,6 +206,7 @@ markers; everything below GENERATED is rebuilt. - [results-library-p3-exports](2026/11/results-library-p3-exports.md) — phase 3; ledger draft/feature/autofit/results_library_epic.md - [results-library-p4-package](2026/11/results-library-p4-package.md) — phase 4; ledger draft/feature/autofit/results_library_epic.md - [results-library-p5b-cortex](2026/11/results-library-p5b-cortex.md) — phase 5b; ledger draft/feature/autofit/results_library_epic.md +- [root-default-test-env-leak](2026/11/root-default-test-env-leak.md) — fixed in commit 748f8c0bb (this PR). The module's autouse `forget_the_resolver` fixture now deletes `PYAUTO_RO… - [rtd-organism-currency](2026/11/rtd-organism-currency.md) — already shipped, closed as a stale draft. PyAutoBrain 1aa2ed4 (#563) renamed `docs/organs/build` to `organs/ha… - [scientist-minimal-starter](2026/11/scientist-minimal-starter.md) — already shipped — Mind#502 / PR #503, record `complete/2026/10/scientist-starter-acceptance.md`; slices PyAuto… - [search-seed-reproducibility](2026/11/search-seed-reproducibility.md) — already shipped — PyAutoFit#1686 (5bf057f2, 2026-10-14; search-ext A4b), record `complete/2026/10/search-ext-a… diff --git a/dashboard.html b/dashboard.html index cdb8a5249..ea1a496bb 100644 --- a/dashboard.html +++ b/dashboard.html @@ -327,8 +327,8 @@ Keep track of decisions and outstanding questions throughout this conversation. After changes, report what was recorded, where it lives and what remains to do. Work on GitHub: -- Open Mind repository: https://github.com/PyAutoLabs/PyAutoMind
Last updated 2026-11-05 22:14:00 UTC
↻ Update

- +- Open Mind repository: https://github.com/PyAutoLabs/PyAutoMind
Last updated 2026-11-05 22:17:24 UTC
↻ Update

+
Batch 2026-11-05-pm — 0 in progress · 0 awaiting review

Nothing to review yet.

Start here

24
@@ -345,7 +345,7 @@

Highest priority (filed as high) — showing 12 of 19

Eyes cluster visualization group: render every cluster/point-source figure for PyAutoEyes✨ featureautolens_visualizationlargesupervisedhigh

-

Fits a slot (ready to run unattended, cheapest to review first) — showing 12 of 81

+

Fits a slot (ready to run unattended, cheapest to review first) — showing 12 of 84

Guard every workspace script against untimed network downloads🧪 testautolens_workspacesmallsafemedium

@@ -526,8 +526,8 @@

Fits a slot (ready to run unattended, cheapest to revie

interferometer-primary-beam-persistence-mirror — filed 2026-10-21 — ready — PyAutoLens claim released 2026-10-21 (point-dataset-positions-panel shipped…

point-plots-yaml-keys-assistant — filed 2026-10-22 — unblocked 2026-10-23 — cosmos-web-ring-notebook merged (autolens_assistant#161, complete/2026/10/cosmos-web-ring-notebook.md)…

-

Backlog

241
-

Lanes: any 233 · local-dev 6

+

Backlog

244
+

Lanes: any 236 · local-dev 6

Human review — 2

Human review: the scaling_relation slam parks (imaging un-parked, multi_galaxy kept)👀 human_reviewautolens_workspacenormal — flagged for review 2026-08-29

-bug — 53 +bug — 54

Fix KNN neighbor search for a partial final point block🐛 bugautoarraymediumsupervisedhigh

@@ -574,6 +574,7 @@

Fits a slot (ready to run unattended, cheapest to revie + @@ -616,7 +617,7 @@

Fits a slot (ready to run unattended, cheapest to revie

-feature — 35 +feature — 36 @@ -646,6 +647,7 @@

Fits a slot (ready to run unattended, cheapest to revie

Context: PyAutoLens issue #542 follow-up (Gap 2, deferred during the✨ featurejax_substructuretoo-largesupervisednormal

dPIE: optional central-dispersion (sigma_0) parameterization✨ featureautogalaxysmallsupervisedlow

+

Release board: local run_logs enrichment✨ featurepyautohandssmallsupervisedlow

Animated logos for PyAutoGalaxy and PyAutoFit✨ featurepyautoscientistmediumsafelow

@@ -737,7 +739,7 @@

Fits a slot (ready to run unattended, cheapest to revie

-test — 8 +test — 9

Physical model check when speeding up smoke tests🧪 testworkspacesmediumsupervisedhigh

Guard every workspace script against untimed network downloads🧪 testautolens_workspacesmallsafemedium

@@ -745,6 +747,7 @@

Fits a slot (ready to run unattended, cheapest to revie +

@@ -765,6 +768,18 @@

Fits a slot (ready to run unattended, cheapest to revie 2026-11-05 +filed +Write compile_repeats from autolens_profiling's jax_compile tooling… + + + +2026-11-05 +filed +Regression test: Nautilus as the EP default_optimiser over… + + + +2026-11-05 issued Likelihood lifecycle phase 4e: ingest the phase-4 wall-time… @@ -772,6 +787,12 @@

Fits a slot (ready to run unattended, cheapest to revie 2026-11-05 filed +Intake injects Memory: citations that match on vocabulary only… + + + +2026-11-05 +filed Filed: 2026-11-05 (phase 2 of autolens_profiling#519; Pulse task… @@ -799,19 +820,19 @@

Fits a slot (ready to run unattended, cheapest to revie Unexplained autodiff-vs-FD gaps in the phase-6 gradient records… - + 2026-11-02 issued Magnification maps 8d: wire into fit subplots and make them pretty - + 2026-11-02 issued Issued: 2026-11-02 - + 2026-11-02 filed Imaging sparse-operator path gives a very different log L from dense… @@ -1039,24 +1060,6 @@

Fits a slot (ready to run unattended, cheapest to revie test_latent_euclid_variables_traces_under_jax_jit went red on main… - -2026-09-24 -filed -euclid_dr1: run the positions gate over DR1 and submit the remodel set - - - -2026-09-23 -filed -multi_dataset/jax_likelihood/delaunay.py asserts the wrong likelihood… - - - -2026-09-18 -filed -autolens_workspace: __Model__ bullets whose profiles or parameter… - -

Pending release

2
diff --git a/dashboard.md b/dashboard.md index 87bc959e2..3e026b77f 100644 --- a/dashboard.md +++ b/dashboard.md @@ -12,7 +12,7 @@ | [Epics](#epics) | 21 | | [In flight](#in-flight) | 8 | | [Planned](#planned) | 9 | -| [Backlog](#backlog) | 241 | +| [Backlog](#backlog) | 244 | | [Recent](#recent) | 50 | | [Pending release](#pending-release) | 2 | @@ -121,7 +121,7 @@ Use the start-dev skill. draft/feature/pyautobrain/close_out_guard_catch_shipped
-**Fits a slot** (ready to run unattended, cheapest to review first) — showing 12 of 81 +**Fits a slot** (ready to run unattended, cheapest to review first) — showing 12 of 84
📋 Guard every workspace script against untimed network downloads — autolens_workspace · small · safe · medium @@ -1163,7 +1163,7 @@ Use the start-dev skill. draft/docs/autolens_assistant/point_plots_yaml_keys.md ## Backlog -Lanes: any 233 · local-dev 6 +Lanes: any 236 · local-dev 6
@@ -1214,7 +1214,7 @@ regenerate the dashboard. If I do not sign it off, file the follow-up with
-bug — 53 +bug — 54
📋 test_latent_euclid_variables_traces_under_jax_jit went red on main: total_source_flux differs by 6% between jax.jit… — euclid · small · supervised · high @@ -1320,6 +1320,14 @@ Use the start-dev skill. draft/bug/euclid/vis_lp_batch_size_kwarg_silently_ignor
+
📋 Intake injects Memory: citations that match on vocabulary only — add… — pyautobrain · small · supervised · medium + +``` +Use the start-dev skill. draft/bug/pyautobrain/intake_injects_memory_citations_that_match_on.md +``` + +
+
📋 Adaptive Delaunay mesh places two mesh pixels 0.001" apart — a degenerate… — autoarray · medium · supervised · medium ``` @@ -1643,7 +1651,7 @@ Use the start-dev skill. draft/bug/autolens/point_source_plot_script_residual_sh
-feature — 35 +feature — 36
📋 Eyes cluster visualization group: render every cluster/point-source figure for PyAutoEyes — autolens_visualization · large · supervised · high @@ -1877,6 +1885,14 @@ Use the start-dev skill. draft/feature/autolens/interferometer_primary_beam_pers
+
📋 Write compile_repeats from autolens_profiling's jax_compile tooling so compile drift can be repeat-summarised — autolens_profiling · small · supervised · low + +``` +Use the start-dev skill. draft/feature/autolens_profiling/write_compile_repeats_from_autolens_profiling_s.md +``` + +
+
📋 Release board: local run_logs enrichment — pyautohands · small · supervised · low ``` @@ -2516,7 +2532,7 @@ Use the start-dev skill. draft/refactor/autoarray/sparse_operator_int32_indexes.
-test — 8 +test — 9
📋 Physical model check when speeding up smoke tests — workspaces · medium · supervised · high @@ -2574,6 +2590,14 @@ Use the start-dev skill. draft/test/workspaces/smoke_workspace_fixes.md
+
📋 Regression test: Nautilus as the EP default_optimiser over PriorFactors — autofit · medium · safe · low + +``` +Use the start-dev skill. draft/test/autofit/regression_test_nautilus_as_the_ep_default.md +``` + +
+
📋 Give imaging/jax_likelihood/mge_group.py a dataset that actually contains group members — autolens_workspace_test · medium · supervised · low ``` @@ -2615,20 +2639,23 @@ Use the start-dev skill. draft/triage/autolens/jit_fit_from_is_vacuous.md | Date | Event | Task | |------|-------|------| | 2026-11-05 | filed | autofit: Samples.with_paths / without_paths break on factor-graph… | +| 2026-11-05 | filed | Write compile_repeats from autolens_profiling's jax_compile tooling… | +| 2026-11-05 | filed | Regression test: Nautilus as the EP default_optimiser over… | | 2026-11-05 | issued | Likelihood lifecycle phase 4e: ingest the phase-4 wall-time… | +| 2026-11-05 | filed | Intake injects Memory: citations that match on vocabulary only… | | 2026-11-05 | filed | Filed: 2026-11-05 (phase 2 of autolens_profiling#519; Pulse task… | | 2026-11-05 | filed | Filed: 2026-11-05 (found by the autolens_profiling#519 worker-route… | | 2026-11-05 | filed | Close-out guard: catch shipped work whose Mind draft was never… | | 2026-11-04 | issued | Autonomous orchestrators phase 4c: run the Dev orchestrator pilot… | | 2026-11-02 | filed | Unexplained autodiff-vs-FD gaps in the phase-6 gradient records… | -| 2026-11-02 | issued | Magnification maps 8d: wire into fit subplots and make them pretty | -| 2026-11-02 | issued | Issued: 2026-11-02 | -| 2026-11-02 | filed | Imaging sparse-operator path gives a very different log L from dense… |
… 10 more (40 left) | Date | Event | Task | |------|-------|------| +| 2026-11-02 | issued | Magnification maps 8d: wire into fit subplots and make them pretty | +| 2026-11-02 | issued | Issued: 2026-11-02 | +| 2026-11-02 | filed | Imaging sparse-operator path gives a very different log L from dense… | | 2026-11-02 | issued | Gradient-correctness sweep: triage and investigate every open… | | 2026-10-31 | issued | Sky orientation (north/east): euclid_dr1 catalogue, paper and… | | 2026-10-30 | filed | Should PyAutoArray flip FITS rows at load so +y is north | @@ -2636,14 +2663,14 @@ Use the start-dev skill. draft/triage/autolens/jit_fit_from_is_vacuous.md | 2026-10-26 | filed | Trim autogalaxy_assistant skills toward their autolens size | | 2026-10-25 | filed | Heart Health rerun cannot publish after main advances | | 2026-10-25 | filed | CI timing must compare equivalent executed job coverage | -| 2026-10-23 | filed | autolens_assistant leg of the PyAutoLabs AI-options page (deferred… | -| 2026-10-23 | filed | @autolens_profiling stale auto-simulated dataset/cluster/simple… | -| 2026-10-23 | filed | A dedicated Documentation conductor in PyAutoBrain |
… 10 more (30 left) | Date | Event | Task | |------|-------|------| +| 2026-10-23 | filed | autolens_assistant leg of the PyAutoLabs AI-options page (deferred… | +| 2026-10-23 | filed | @autolens_profiling stale auto-simulated dataset/cluster/simple… | +| 2026-10-23 | filed | A dedicated Documentation conductor in PyAutoBrain | | 2026-10-22 | filed | point-plots-yaml-keys-assistant | | 2026-10-21 | filed | interferometer-primary-beam-persistence-mirror | | 2026-10-21 | filed | PyAutoLens mirror of the interferometer primary-beam persistence… | @@ -2651,14 +2678,14 @@ Use the start-dev skill. draft/triage/autolens/jit_fit_from_is_vacuous.md | 2026-10-21 | filed | Matrix-free interferometer inversion, phase 5b: profiling note… | | 2026-10-21 | issued | Matrix-free interferometer inversion for very large rectangular… | | 2026-10-21 | filed | Interferometer primary beam: workspace example and docs | -| 2026-10-21 | filed | Cluster likelihood scripts: image-plane manual check disagrees with… | -| 2026-10-16 | filed | Re-measure the shapelets/modeling.py SLOW park (#586) under the… | -| 2026-10-14 | filed | @autofit_workspace six searches/ scripts fail on main at… |
… 10 more (20 left) | Date | Event | Task | |------|-------|------| +| 2026-10-21 | filed | Cluster likelihood scripts: image-plane manual check disagrees with… | +| 2026-10-16 | filed | Re-measure the shapelets/modeling.py SLOW park (#586) under the… | +| 2026-10-14 | filed | @autofit_workspace six searches/ scripts fail on main at… | | 2026-10-14 | filed | Cortex output summaries — phase 2 | | 2026-10-08 | filed | JAX_ENABLE_X64=False is overridden to True, so the fp32 inference… | | 2026-10-07 | filed | Upstream the DR1 final-catalogue tooling to the pipeline, with a… | @@ -2666,14 +2693,14 @@ Use the start-dev skill. draft/triage/autolens/jit_fit_from_is_vacuous.md | 2026-10-02 | filed | knn-partial-point-block | | 2026-10-02 | filed | Fix Sibson interpolation at internal edges | | 2026-10-02 | filed | Fix KNN neighbor search for a partial final point block | -| 2026-10-01 | filed | Sparse interferometer terms: NUFFT ignores the mask origin and… | -| 2026-10-01 | filed | Interferometer log_evidence fails (LinAlgError / NaN) at large… | -| 2026-10-01 | filed | Interferometer galaxy_image_dict drops a mixed galaxy's ordinary… |
… 10 more (10 left) | Date | Event | Task | |------|-------|------| +| 2026-10-01 | filed | Sparse interferometer terms: NUFFT ignores the mask origin and… | +| 2026-10-01 | filed | Interferometer log_evidence fails (LinAlgError / NaN) at large… | +| 2026-10-01 | filed | Interferometer galaxy_image_dict drops a mixed galaxy's ordinary… | | 2026-09-29 | filed | PlotterEllipse.fit_ellipse writes every variant to… | | 2026-09-27 | filed | Sparse interferometer inversion: jax.grad of the log-evidence terms… | | 2026-09-27 | filed | Same-class q-clamp and bare-sqrt ellipticity gradient sites… | @@ -2681,9 +2708,6 @@ Use the start-dev skill. draft/triage/autolens/jit_fit_from_is_vacuous.md | 2026-09-26 | filed | bump_colab_urls.sh: cover autolens_assistant Colab links | | 2026-09-26 | filed | Repo cleanup: retire the Abell 1201 worktree and local raw data | | 2026-09-25 | filed | test_latent_euclid_variables_traces_under_jax_jit went red on main… | -| 2026-09-24 | filed | euclid_dr1: run the positions gate over DR1 and submit the remodel set | -| 2026-09-23 | filed | multi_dataset/jax_likelihood/delaunay.py asserts the wrong likelihood… | -| 2026-09-18 | filed | autolens_workspace: __Model__ bullets whose profiles or parameter… |
@@ -2759,7 +2783,7 @@ _Dates come from each task's registry entry — `lifecycle.py dates` reports any
-61 prompt(s) with unknown theme keyword(s) — not in [`themes.md`](themes.md), so they group loudly rather than silently. Correct the prompt, or add the keyword to the vocabulary. +63 prompt(s) with unknown theme keyword(s) — not in [`themes.md`](themes.md), so they group loudly rather than silently. Correct the prompt, or add the keyword to the vocabulary.
Unknown theme keywords @@ -2772,6 +2796,7 @@ _Dates come from each task's registry entry — `lifecycle.py dates` reports any - `draft/feature/autofit/certified_solver_batched_guard_c2.md — unknown theme keyword(s): inversion` - `draft/feature/autofit/results_library_epic.md — unknown theme keyword(s): hpc, euclid, results, aggregator` - `draft/feature/autolens/coolest_pixel_grid_export.md — unknown theme keyword(s): coolest, interop, euclid` +- `draft/feature/autolens_profiling/write_compile_repeats_from_autolens_profiling_s.md — unknown theme keyword(s): measurement-tools` - `draft/feature/euclid/catalogue_extension_coolest_mass_fits.md — unknown theme keyword(s): euclid, catalogue` - `draft/feature/euclid/euclid_dr1_prep_epic.md — unknown theme keyword(s): euclid` - `draft/feature/euclid/single_process_cpu_route_jax_vis_lp_numba_vis_pix.md — unknown theme keyword(s): euclid, jax, hpc` @@ -2813,6 +2838,7 @@ _Dates come from each task's registry entry — `lifecycle.py dates` reports any - `draft/refactor/autolens/witt_wynne_solver_library_home.md — unknown theme keyword(s): euclid` - `draft/refactor/autonerves/config_yaml_parse_cache.md — unknown theme keyword(s): performance, ci` - `draft/docs/autocti/installation_docs_arcticpy_recipe.md — unknown theme keyword(s): install, docs` +- `draft/test/autofit/regression_test_nautilus_as_the_ep_default.md — unknown theme keyword(s): nautilus` - `draft/release/arcticpy/upstream_packaging_pr.md — unknown theme keyword(s): install, upstream` - `draft/maintenance/autocti/cti_upkeep_epic.md — unknown theme keyword(s): infrastructure` - `draft/maintenance/euclid/skip_fit_output_no_longer_gates_save_results_docs_drift.md — unknown theme keyword(s): euclid, docs` diff --git a/draft/bug/pyautobrain/intake_injects_memory_citations_that_match_on.md b/draft/bug/pyautobrain/intake_injects_memory_citations_that_match_on.md new file mode 100644 index 000000000..30ccc428c --- /dev/null +++ b/draft/bug/pyautobrain/intake_injects_memory_citations_that_match_on.md @@ -0,0 +1,28 @@ +# Intake injects `Memory:` citations that match on vocabulary only — add… + +Type: bug +Target: PyAutoBrain +Repos: +- PyAutoBrain +Themes: +- mind-workflow +Difficulty: small +Autonomy: supervised +Priority: medium +Status: formalised +Filed: 2026-11-05 +Consequence: glance +Witness: a test classifies a library-targeted tooling prompt (e.g. "write compile_repeats from the jax_compile tooling") against a fixture digest whose only overlap is generic words ("model", "profile", "fit") and asserts no `Memory:` line is written, while a prompt naming a digest page's distinctive terms still gets one; `pytest PyAutoBrain/tests -q` green. +Review-minutes: 3 +Unattended: ready + +The organ-target gate shipped (557f8e0 / #561), but the second half of the original suggestion — +"skip PyAutoMemory citation … when the best digest score is below a floor" — never did. On +2026-11-05 intake wrote `Memory: wiki/galaxies/sources/massive-ellipticals.md; reading-queue.md; +wiki/lensing/sources/dark-matter-substructure.md` onto an autolens_profiling tooling prompt and a +similar line onto a PyAutoFit EP regression-test prompt; both were removed by hand, as earlier +sessions did on 2026-11-03. Add a score floor in `memory_citations()` / `_with_memory` +(`agents/conductors/intake/_intake.py`), calibrated on a few real prompts, and keep "no hits → no +line". `reading-queue.md` as a citation is a smell on its own (it is an index, not a source). + + diff --git a/draft/feature/autolens_profiling/write_compile_repeats_from_autolens_profiling_s.md b/draft/feature/autolens_profiling/write_compile_repeats_from_autolens_profiling_s.md new file mode 100644 index 000000000..3a63e0636 --- /dev/null +++ b/draft/feature/autolens_profiling/write_compile_repeats_from_autolens_profiling_s.md @@ -0,0 +1,27 @@ +# Write `compile_repeats` from autolens_profiling's jax_compile tooling so compile drift can be repeat-summarised + +Type: feature +Target: autolens_profiling +Repos: +- autolens_profiling +Themes: +- measurement-tools +Difficulty: small +Autonomy: supervised +Priority: low +Status: formalised +Filed: 2026-11-05 +Consequence: judge +Witness: a jax_compile record written by the tooling carries an integer `compile_repeats` (the number of compile timings its `compile_s` summarises); the Brain profiling conductor reports a drift between two such records with `comparison: repeat-summarised` instead of the single-sample caveat. +Review-minutes: 5 +Unattended: ready + +PyAutoBrain#588 (record `complete/2026/11/compile-drift-single-sample.md`) made the profiling +conductor label every compile-drift row `single-sample` unless both endpoints carry +`compile_repeats >= 2` (P7's `single_jit_repeats` rule). No producer writes the field yet, so +every real drift today is reported as a gross single-sample flag. Decide whether the jax_compile +scripts should time N cold compiles (cost: N× compile time per cell) and record N plus the summary +estimator; if repeats are too expensive, record `compile_repeats: 1` explicitly so the caveat is +evidence-based rather than defaulted. + + diff --git a/draft/test/autofit/regression_test_nautilus_as_the_ep_default.md b/draft/test/autofit/regression_test_nautilus_as_the_ep_default.md new file mode 100644 index 000000000..a7f4e6320 --- /dev/null +++ b/draft/test/autofit/regression_test_nautilus_as_the_ep_default.md @@ -0,0 +1,26 @@ +# Regression test: Nautilus as the EP `default_optimiser` over PriorFactors + +Type: test +Target: PyAutoFit +Repos: +- PyAutoFit +Themes: +- graphical-ep +- nautilus +Difficulty: medium +Autonomy: safe +Priority: low +Status: formalised +Filed: 2026-11-05 +Consequence: glance +Witness: a PyAutoFit unit test builds an `EPOptimiser` with `default_optimiser=af.Nautilus(number_of_cores=1)` over a `FactorGraphModel` with one AnalysisFactor plus its PriorFactors and runs one step without AttributeError (fast settings / a stubbed sampler run are fine). +Review-minutes: 3 +Unattended: ready + +The bug (Nautilus `_fit` reading `analysis._use_jax` unguarded on a PriorFactor) is gone since +PyAutoFit 196abf39a (`Analysis.is_jax` = `bool(getattr(self, "_use_jax", False))`, inherited by +`PriorFactor`), and its draft was closed 2026-11-05 as superseded +(`complete/2026/11/nautilus-ep-use-jax-guard.md`). The regression test the original draft asked +for was never added, so nothing stops the unguarded read coming back. Add it. + + diff --git a/scripts/ledger_merge.py b/scripts/ledger_merge.py index 14217a8d7..470c28896 100755 --- a/scripts/ledger_merge.py +++ b/scripts/ledger_merge.py @@ -54,6 +54,7 @@ import argparse import fnmatch +import os import subprocess import sys from pathlib import Path @@ -281,7 +282,7 @@ def resolve_conflicts(cwd=None) -> tuple[list[str], list[str]]: _git("checkout", "--ours", "--", path, cwd=root) _git("add", "--", path, cwd=root) resolved.append( - f"{path} (render: main's copy, regenerated after the merge)" + f"{path} (render: regenerated after the merge)" ) elif path in ENTRY_MERGED_FILES: stages = [_git("show", f":{n}:{path}", cwd=root) for n in (1, 2, 3)] @@ -300,6 +301,88 @@ def resolve_conflicts(cwd=None) -> tuple[list[str], list[str]]: return resolved, unresolved +def _brain_renderer(root: Path): + """The Brain dashboard renderer beside this Mind, or None. The renderer is + the Brain's (the organ boundary), so a Mind-only checkout cannot regenerate + the dashboard — `dashboard_refresh.yml` heals it on main instead.""" + candidates = [] + if os.environ.get("PYAUTO_BRAIN"): + candidates.append(Path(os.environ["PYAUTO_BRAIN"])) + candidates += [root.parent / "PyAutoBrain", root.parent / "organs" / "PyAutoBrain"] + for brain in candidates: + script = brain / "agents" / "conductors" / "intake" / "_intake.py" + if script.is_file(): + return script + return None + + +def regenerate_renders(root: Path) -> list[str]: + """Re-render every GENERATED_FILES path on the (merged) tree and stage them. + Returns one line per render: regenerated, or skipped with the reason.""" + report = [] + index = subprocess.run( + [sys.executable, str(root / "scripts" / "lifecycle.py"), "index", "--apply"], + capture_output=True, text=True, cwd=root, + ) + report.append("complete/index.md: regenerated" if index.returncode == 0 + else f"complete/index.md: NOT regenerated ({index.stderr.strip()[-200:]})") + renderer = _brain_renderer(root) + if renderer is None: + report.append("dashboard: NOT regenerated (no PyAutoBrain beside this Mind; " + "set PYAUTO_BRAIN, or let dashboard_refresh.yml heal main)") + else: + dash = subprocess.run( + [sys.executable, str(renderer), "--mind", str(root), "--apply", "dashboard"], + capture_output=True, text=True, cwd=root, + ) + report.append("dashboard.md / dashboard.html / state.json: regenerated" + if dash.returncode == 0 + else f"dashboard: NOT regenerated ({dash.stderr.strip()[-200:]})") + present = [p for p in GENERATED_FILES if (root / p).exists()] + if present: + _git("add", "--", *present, cwd=root) + return report + + +def sync_with_base(base: str = "origin/main", cwd=None, render=regenerate_renders): + """Bring a Mind branch up to date with `base` the way the ledger-merge + workflow does, for branches that workflow never touches (session branches, + PR branches holding code): `git merge --no-commit --no-ff `, settle + what the ledger grammar can (`resolve_conflicts`), re-render the generated + files on the merged tree, and leave the merge staged for the caller to + commit. Returns (status, lines) with status one of `up-to-date`, + `ready` (staged, commit it), `blocked` (unresolved paths; merge left in + progress) or `dirty` (refused: uncommitted changes).""" + root = Path(cwd) if cwd else Path(__file__).resolve().parents[1] + if _git("status", "--porcelain", cwd=root).stdout.strip(): + return "dirty", ["refused: the working tree has uncommitted changes — commit or stash them first"] + merge = _git("merge", "--no-commit", "--no-ff", base, cwd=root) + if "Already up to date" in merge.stdout: + return "up-to-date", [f"already up to date with {base}"] + lines = [] + if merge.returncode != 0: + unmerged = _git("diff", "--name-only", "--diff-filter=U", cwd=root).stdout.split() + if not unmerged: + return "blocked", [f"git merge {base} failed: {(merge.stderr or merge.stdout).strip()}"] + resolved, unresolved = resolve_conflicts(root) + lines += [f"resolved: {line}" for line in resolved] + if unresolved: + lines += [f"unresolved: {line}" for line in unresolved] + lines.append("merge left in progress — settle the unresolved paths, re-run the " + "renders, then commit (or `git merge --abort`)") + return "blocked", lines + lines += [f"render: {line}" for line in render(root)] + lines.append("merge staged — review, then `git commit` (the merge message is prefilled)") + return "ready", lines + + +def _sync_cli(args) -> int: + status, lines = sync_with_base(args.base, args.root) + for line in lines: + print(line) + return 0 if status in ("up-to-date", "ready") else 1 + + def _resolve_cli(args) -> int: resolved, unresolved = resolve_conflicts(args.root) for line in resolved: @@ -355,11 +438,22 @@ def main(argv=None) -> int: res.add_argument( "--root", help="the repo with the merge in progress (default: this one)" ) + syn = sub.add_parser( + "sync", + help="merge a base ref into this branch, settle ledger conflicts and " + "re-render the generated files (for branches the ledger-merge " + "workflow does not handle)", + ) + syn.add_argument("--base", default="origin/main", + help="the ref to merge in (default origin/main; fetch it first)") + syn.add_argument("--root", help="the Mind checkout (default: this one)") args = parser.parse_args(argv) if args.command == "merge-entries": return _merge_entries_cli(args) if args.command == "resolve": return _resolve_cli(args) + if args.command == "sync": + return _sync_cli(args) # Source precedence: explicit paths, then --base, then stdin. `--base` must # never read stdin: a Claude Code web/mobile session runs commands with a diff --git a/state.json b/state.json index b8bb799dd..529062340 100644 --- a/state.json +++ b/state.json @@ -4,7 +4,7 @@ "repo": "PyAutoMind", "status": "yellow", "headline": "YELLOW \u2014 24 picks \u00b7 8 in flight", - "updated": "2026-11-05T22:14:00Z", + "updated": "2026-11-05T22:17:24Z", "pages_url": "https://pyautolabs.github.io/PyAutoMind/", "items": [ { diff --git a/tests/test_ledger_merge.py b/tests/test_ledger_merge.py index 7852b2c78..f872ad613 100644 --- a/tests/test_ledger_merge.py +++ b/tests/test_ledger_merge.py @@ -400,3 +400,59 @@ def test_workflow_namespaces_use_same_ledger_gate(tmp_path, namespace): cwd=repo, capture_output=True, text=True) assert denied.returncode == 1 assert "scripts/change.py" in denied.stdout + + +# --------------------------------------------------------------------------- # +# sync: the local twin of the workflow's merge, for branches it never touches +# --------------------------------------------------------------------------- # +def _fake_render(calls): + def render(root): + calls.append(root) + (root / "dashboard.md").write_text("render merged\n") + _git(root, "add", "dashboard.md") + return ["dashboard: regenerated"] + return render + + +def test_sync_merges_main_settles_the_ledger_and_rerenders(tmp_path): + repo = _ledger_repo(tmp_path) + _git(repo, "checkout", "-q", "claude/x") # a session branch, behind main + calls = [] + status, lines = ledger_merge.sync_with_base("main", repo, render=_fake_render(calls)) + assert status == "ready", lines + assert calls == [repo], "renders are regenerated on the merged tree" + assert any(line.startswith("resolved: active.md") for line in lines) + # the branch closed b, main issued c: both survive the entry merge + assert (repo / "active.md").read_text() == PRE + _entry("a") + _entry("c").rstrip("\n") + "\n" + assert (repo / "dashboard.md").read_text() == "render merged\n" + assert _git(repo, "diff", "--name-only", "--diff-filter=U").stdout == "" + assert (repo / ".git" / "MERGE_HEAD").exists(), "left staged for the caller to commit" + + +def test_sync_is_a_no_op_when_up_to_date_and_refuses_a_dirty_tree(tmp_path): + repo = _ledger_repo(tmp_path) + calls = [] + assert ledger_merge.sync_with_base("main", repo, render=_fake_render(calls))[0] == "up-to-date" + assert calls == [] + _git(repo, "checkout", "-q", "claude/x") + (repo / "active.md").write_text("uncommitted\n") + status, _ = ledger_merge.sync_with_base("main", repo, render=_fake_render(calls)) + assert status == "dirty" and calls == [] + assert not (repo / ".git" / "MERGE_HEAD").exists() + + +def test_sync_stops_before_rendering_when_a_conflict_needs_a_human(tmp_path): + repo = _ledger_repo(tmp_path) + _git(repo, "checkout", "-q", "claude/x") + (repo / "notes.txt").write_text("branch\n") + _git(repo, "add", "notes.txt") + _git(repo, "commit", "-qm", "branch notes") + _git(repo, "checkout", "-q", "main") + (repo / "notes.txt").write_text("main\n") + _git(repo, "add", "notes.txt") + _git(repo, "commit", "-qm", "main notes") + _git(repo, "checkout", "-q", "claude/x") + calls = [] + status, lines = ledger_merge.sync_with_base("main", repo, render=_fake_render(calls)) + assert status == "blocked" and calls == [] + assert "unresolved: notes.txt" in lines diff --git a/tests/test_repos_sync_root_default.py b/tests/test_repos_sync_root_default.py index 472996b4f..9ac1b37bd 100644 --- a/tests/test_repos_sync_root_default.py +++ b/tests/test_repos_sync_root_default.py @@ -45,8 +45,13 @@ def workspace_root_reason(): @pytest.fixture(autouse=True) -def forget_the_resolver(): - """Each test brings its own stub; the import cache must not leak.""" +def forget_the_resolver(monkeypatch): + """Each test brings its own stub; the import cache must not leak — and + neither may the caller's environment. An exported PYAUTO_ROOT (which the + Brain CLI exports for its own children) is "the operator's word" to + workspace_root, so a test that does not set it must not inherit it.""" + monkeypatch.delenv("PYAUTO_ROOT", raising=False) + monkeypatch.delenv("PYAUTO_ROOT_REASON", raising=False) before = list(sys.path) repos_sync._RESOLVER.clear() sys.modules.pop("_pyauto_root", None) diff --git a/tests/test_session_bootstrap.py b/tests/test_session_bootstrap.py index c466222ac..0ecc2b3c5 100644 --- a/tests/test_session_bootstrap.py +++ b/tests/test_session_bootstrap.py @@ -949,6 +949,12 @@ def test_the_hook_survives_an_unwritable_tools_dir(tmp_path): _break_tool_env(tool, session_venv, tmp_path) (tool / "bin").chmod(0o500) # can read + traverse, cannot replace + if os.access(tool / "bin", os.W_OK): + # root (a container, CI as root) ignores the mode bits, so the failure + # path this test drives cannot be produced — skip rather than pass + # vacuously or fail on the environment. + (tool / "bin").chmod(0o755) + pytest.skip("cannot make a directory unwritable here (running as root?)") try: r = _call_hook_function("repair_uv_tools", venv=session_venv, extra_env={"PYAUTO_UV_TOOLS_DIR": str(tools)})