diff --git a/draft/bug/priors/12_single_source_density_refactor.md b/active/12_single_source_density_refactor.md similarity index 100% rename from draft/bug/priors/12_single_source_density_refactor.md rename to active/12_single_source_density_refactor.md diff --git a/draft/bug/priors/13_collapse_prior_and_message.md b/active/13_collapse_prior_and_message.md similarity index 100% rename from draft/bug/priors/13_collapse_prior_and_message.md rename to active/13_collapse_prior_and_message.md diff --git a/draft/bug/priors/09_prior_property_tests.md b/complete/2026/08/prior-property-tests.md similarity index 72% rename from draft/bug/priors/09_prior_property_tests.md rename to complete/2026/08/prior-property-tests.md index eb523f12..a883b337 100644 --- a/draft/bug/priors/09_prior_property_tests.md +++ b/complete/2026/08/prior-property-tests.md @@ -1,3 +1,53 @@ +Property-based correctness sweep over every concrete `Prior` subclass — census +finding C3, the Phase 3 safety net of the priors/messages cleanup (hub +PyAutoFit#1331). Issue PyAutoFit#1497; **PR PyAutoFit#1499, merged 2026-08-18 +as `21288bb` with all checks green** (unittest 3.12 + 3.13, docs). Closes the +loop the census opened: the nine bug fixes shipped in July (#1345/#1348) are +now locked as class-wide invariants, not just pointwise regressions. + +- New `test_autofit/mapper/prior/test_prior_properties.py` — 134 parametrised + tests, five properties over Uniform/LogUniform/Gaussian/LogGaussian/ + TruncatedGaussian (two parameterisations each): P1 `cdf(value_for(u)) ≈ u` + (1e-6); P2 normalisation three ways — `exp(log_prior_from_value + + log_normalisation())` integrates to 1 (locks the #1331 Option A contract), + the message physical-density path integrates to 1, and the generic + exponential-family pdf integrates to 1 for direct messages **including + `TruncatedNormalMessage`** (the exclusion that let #1331-04 survive); P3 + finite-difference gradient parity between `log_prior_from_value` and the + physical log density (the #1266 sign-convention canary); P4 `with_limits` + constructs for every family with documented semantics (hard-limit families + hit the limits exactly; Gaussian families centre between limits, and the + LogGaussian keeps positive support per the #1331-01 fix); P5 + `from_mode(m, V)` reproduces mean and variance at V≠1 discriminating points + for Normal and Gamma (locks #1331-D3 — V=1 cannot discriminate the + historical inverted formula). +- Also carried `bug/priors/11` §2 (see [[transformed-message-semantics-doc]]). +- Every property was numerically validated against clean main before being + committed as an assertion; NumPy-only per the house rule (EP-level coverage + belongs to the EP framework review, [[ep-framework-review]]). + +**Key trap / new finding:** `TransformedMessage.logpdf`/`pdf` omit the +transform Jacobian — the generic path returns the *base-space* density at +physical coordinates (`UniformPrior(0,1).message.pdf` integrates to exactly +1/(2√π) ≈ 0.282, not 1; LogUniform(0.01,100) to 15.83) while `factor()` is +correct, and the #1334 module docstring claims the opposite. Same failure +shape as #1331-04. Filed as **PyAutoFit#1498** + intaken as +`draft/bug/priors/15_transformed_message_logpdf_jacobian.md`; the tests +assert the physical density via `factor()` (`physical_log_density` helper) +and cite #1498 at the site so they can be tightened once adjudicated. + +**API notes for future sweeps:** `with_limits` is an instance method on +Uniform (abstract) but a classmethod on the Gaussian families; +`GammaMessage.value_for` deliberately raises (no inverse CDF) so infinite +supports are truncated at mean ± 40σ for integration; `prior.cdf` works on +every family via the message and round-trips exactly. + +Sibling work filed the same day: the bundled 12+13 design issue +PyAutoFit#1500 (single-source density + Prior/Message collapse), which the +census retirement and this sweep were the groundwork for. + +## Original prompt + # `@PyAutoFit` Add property-based correctness tests for every `Prior` subclass Type: bug diff --git a/draft/bug/priors/11_transformed_message_semantics_doc.md b/complete/2026/08/transformed-message-semantics-doc.md similarity index 85% rename from draft/bug/priors/11_transformed_message_semantics_doc.md rename to complete/2026/08/transformed-message-semantics-doc.md index 211693a7..c2d56961 100644 --- a/draft/bug/priors/11_transformed_message_semantics_doc.md +++ b/complete/2026/08/transformed-message-semantics-doc.md @@ -1,11 +1,38 @@ +`TransformedMessage` semantics documentation — census finding C6, +`bug/priors/11`. Shipped in two halves, both now on PyAutoFit main: + +- **§1 (asymmetric reversal convention)** — shipped 2026-07-10 via + PyAutoFit#1333 / PR#1334 as part of EP-review Phase 2: docstrings on + `_transform` / `_inverse_transform` in `messages/composed_transform.py` + plus the module docstring's worked `UniformPrior(0, 2).value_for(0.5)` + example and `autofit/graphical/README.md` §2 pointer. +- **§2 (`LinearShiftTransform` stores the reciprocal of the intuitive + scale)** — shipped 2026-08-18 riding PR PyAutoFit#1499 (merged `21288bb`, + the [[prior-property-tests]] PR): class docstring stating that + `shift`/`scale` describe physical space, the stored parent Jacobian is + `DiagonalMatrix(1/scale)` because `transform()` runs physical → base, and + `log_det = -log(scale)` follows; cites #1266 as the historical cost of + getting the reciprocal backwards. + +The prompt's optional `physical_scale=` rename was **not** done — the audit's +own leaning ("docs alone are fine if the bijector migration stays on the +roadmap") applied, and the bijector question is now explicitly parked behind +the PyAutoFit#1500 design decision. + +Note: the same PR's test work surfaced that `TransformedMessage.logpdf` +contradicts the #1334 module docstring (Jacobian never accumulated) — that is +PyAutoFit#1498 / `draft/bug/priors/15`, deliberately outside this doc task. + +## Original prompt + # `@PyAutoFit` `TransformedMessage` reversal convention is undocumented foot-gun Type: bug Target: priors -Difficulty: large +Difficulty: small Autonomy: supervised Priority: normal -Status: HALF SHIPPED — edge 1 is documented, edge 2 is not (2026-08-09) +Status: HALF SHIPPED — edge 1 is documented, edge 2 is not (2026-08-09; Difficulty dropped large → small per the note below, 2026-08-18) ## 2026-08-09 — the reversal-convention half landed; the reciprocal half did not diff --git a/complete/index.md b/complete/index.md index 2159725e..a35bfcc1 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. -1023 records across 7 buckets. +1025 records across 7 buckets. ## Highlights @@ -111,6 +111,7 @@ _(curate hard-won records here — survives regeneration.)_ - [power-law-omega-convergence](2026/08/power-law-omega-convergence.md) — Bounded the fixed 20-term JAX PowerLaw omega recurrence across the packaged slope and ellipticity priors, meas… - [pr-ci-for-own-test-suite](2026/08/pr-ci-for-own-test-suite.md) - [pre-build-stages-untracked-wip](2026/08/pre-build-stages-untracked-wip.md) — CLOSED completed +- [prior-property-tests](2026/08/prior-property-tests.md) - [prior-support-clipper](2026/08/prior-support-clipper.md) — Shipped `AbstractClipper` / `ClipperNone` / `ClipperPriorBox` in - [profile-validation-resample-recovery](2026/08/profile-validation-resample-recovery.md) — Shipped the approved narrow compatibility fix: invalid profile construction is now both a direct `ValueError` … - [purge-autocti-dataset-1d-overview](2026/08/purge-autocti-dataset-1d-overview.md) — no GitHub issue — the leftover from `autocti-util-dataset-export`, executed on direct human instruction "do th… @@ -144,6 +145,7 @@ _(curate hard-won records here — survives regeneration.)_ - [tenant-firewall-hygiene-extras](2026/08/tenant-firewall-hygiene-extras.md) — auto-closed by the merge - [test-mode-fit-exception-finalization](2026/08/test-mode-fit-exception-finalization.md) — `PYAUTO_TEST_MODE=1` no longer finalizes a model point whose reconstruction raises `FitException`; it substitu… - [test-mode-samples-info-hook-contract](2026/08/test-mode-samples-info-hook-contract.md) — `NonLinearSearch._test_mode_samples_info()`'s docstring told subclasses +- [transformed-message-semantics-doc](2026/08/transformed-message-semantics-doc.md) - [uniform-prior-bounds-numpy-path](2026/08/uniform-prior-bounds-numpy-path.md) — auto-closed by the merge's `Closes` line - [version-skew-yank-awareness](2026/08/version-skew-yank-awareness.md) - [wiki-provenance-restamp](2026/08/wiki-provenance-restamp.md) diff --git a/dashboard.md b/dashboard.md index 37d23bfb..fb2d79fc 100644 --- a/dashboard.md +++ b/dashboard.md @@ -8,10 +8,10 @@ Tasks only — the organism's health lives with the Heart (`/health`), not here. | Where | Count | |-------|------:| -| [In flight](#in-flight) (`active/`) | 3 | -| [Parked](#parked) (`parked.md`) | 1 | +| [In flight](#in-flight) (`active/`) | 5 | +| [Parked](#parked) (`parked.md`) | 3 | | [Planned](#planned) (`planned.md`) | 7 | -| [Backlog](#backlog) (`draft/`) | 127 | +| [Backlog](#backlog) (`draft/`) | 124 | 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) @@ -45,6 +45,8 @@ Live on GitHub: [open issues](https://github.com/search?q=org%3APyAutoLabs+is%3A Issued — each has an open GitHub issue and usually a branch. The full record for each is in [`active.md`](active.md). +- [`@PyAutoFit` Refactor: each density should live in one place, not](active/12_single_source_density_refactor.md) — [issue #1500](https://github.com/PyAutoLabs/PyAutoFit/issues/1500) +- [`@PyAutoFit` Refactor: collapse the `Prior` / `Message` two-layer hierarchy](active/13_collapse_prior_and_message.md) — [issue #1500](https://github.com/PyAutoLabs/PyAutoFit/issues/1500) - [PyAutoReduce validation: slacs1430+4105 ACS reduction vs trusted legacy dataset](active/pyautoreduce_slacs1430_acs_comparison.md) - [Reconstructing a stored sample raises through `ignore_assertions=True`](active/to_instance_guard_gap.md) — [issue #1486](https://github.com/PyAutoLabs/PyAutoFit/issues/1486) — library-dev — WORKSPACE HALF SHIPPED; the PyAutoFit hardening (#1486) is what remains - [Version-stamp sync to 2026.8.17.1 + release-sed guards](active/version_stamp_sync_and_release_sed_guards.md) — [issue #235](https://github.com/PyAutoLabs/PyAutoHands/issues/235) — pr-open (https://github.com/PyAutoLabs/PyAutoLens/pull/700) @@ -54,8 +56,10 @@ Issued — each has an open GitHub issue and usually a branch. The full record f Started or scoped, not currently in flight — resume by moving the row back to `active.md`. Full detail in [`parked.md`](parked.md).
-1 task(s) +3 task(s) +- **single-source-density-design** — [issue #1500](https://github.com/PyAutoLabs/PyAutoFit/issues/1500) +- **prior-message-collapse-design** — [issue #1500](https://github.com/PyAutoLabs/PyAutoFit/issues/1500) - **pyautoreduce-slacs1430-acs-comparison**
@@ -79,10 +83,10 @@ Scoped but not started; some are not yet prompt files. Full detail in [`planned. ## Backlog -**127** filed prompts, not started. Each section is sorted most-pickable first (priority, then size). +**124** filed prompts, not started. Each section is sorted most-pickable first (priority, then size).
-bug — 35 +bug — 32 - [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 - [`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 @@ -110,11 +114,8 @@ Scoped but not started; some are not yet prompt files. Full detail in [`planned. - [interferometer Delaunay pixelization — non-PD FitException in test-mode bypass](draft/bug/autolens/interferometer_delaunay_nonpd_fitexception.md) — autolens · medium · supervised · normal - [JAX point-source smoke sentinel: point.py returns -1e99 instead of -83.38](draft/bug/autolens/jax_point_source_point_smoke_sentinel.md) — autolens · medium · supervised · normal - [JIT cache not hit in modeling_visualization delaunay/rectangular scripts](draft/bug/autolens/jit_cache_not_hit_modeling_visualization.md) — autolens · medium · supervised · normal -- [`@PyAutoFit` Add property-based correctness tests for every `Prior` subclass](draft/bug/priors/09_prior_property_tests.md) — priors · large · supervised · normal -- [`@PyAutoFit` `TransformedMessage` reversal convention is undocumented foot-gun](draft/bug/priors/11_transformed_message_semantics_doc.md) — priors · large · supervised · normal +- [`@PyAutoFit` `TransformedMessage.logpdf`/`pdf` omit the transform Jacobian](draft/bug/priors/15_transformed_message_logpdf_jacobian.md) — priors · medium · supervised · normal - [Resolve release-profile timeout scripts deliberately](draft/bug/health_fixes/release_timeout_policy.md) — health_fixes · too-large · supervised · normal -- [`@PyAutoFit` Refactor: each density should live in one place, not](draft/bug/priors/12_single_source_density_refactor.md) — priors · too-large · supervised · normal -- [`@PyAutoFit` Refactor: collapse the `Prior` / `Message` two-layer hierarchy](draft/bug/priors/13_collapse_prior_and_message.md) — priors · too-large · supervised · normal - [`@PyAutoFit` Refactor: replace hand-rolled `AbstractDensityTransform` with `tfp.bijectors` / `numpyro.distributions.transforms`](draft/bug/priors/14_replace_transform_stack_with_bijectors.md) — priors · too-large · supervised · normal - [Priors & Messages cleanup — tracker](draft/bug/priors/z_features.md) — priors · too-large · supervised · normal - [`add_notebook_quotes` mistakes a code string literal's closing delimiter for a](draft/bug/hands/notebook_quotes_string_literal_closing_delimiter.md) — hands · small · safe · low diff --git a/draft/bug/priors/15_transformed_message_logpdf_jacobian.md b/draft/bug/priors/15_transformed_message_logpdf_jacobian.md new file mode 100644 index 00000000..95d1188d --- /dev/null +++ b/draft/bug/priors/15_transformed_message_logpdf_jacobian.md @@ -0,0 +1,69 @@ +# `@PyAutoFit` `TransformedMessage.logpdf`/`pdf` omit the transform Jacobian + +Type: bug +Target: priors +Difficulty: medium +Autonomy: supervised +Priority: normal +Status: formalised — issue filed (PyAutoFit#1498), awaiting adjudication + +Found 2026-08-18 while implementing the #1497 property sweep (prompt +`bug/priors/09`). Same failure *shape* as census finding A4 (#1331-04): a +generic-interface density path is silently wrong while the direct paths are +right. + +## The finding + +`TransformedMessage` inherits `MessageInterface.logpdf` (the natural-parameter +path). Its overrides forward `natural_parameters`, `calc_log_base_measure` and +`to_canonical_form` to the base message — `to_canonical_form` is +`@transform`-decorated, so the physical input is mapped to base coordinates — +but **no `log_det` change-of-variables term is ever added**. `logpdf(x)` at a +physical `x` therefore returns the *base-space* density at the mapped point, +not the physical density. `TransformedMessage.factor(x)` does it correctly +(`base.logpdf(transform(x)) + log_det`). + +Reproduction on `main` @ `7d4d931` (exact numbers): + +- `af.UniformPrior(0,1).message.logpdf(0.7)` = −1.05644 (physical density is + 1.0 → expect 0.0); `factor(0.7)` = 0.0 ✓ +- `∫ exp(logpdf)` over [0,1] = **0.282095 = 1/(2√π)**, not 1.0; + `∫ exp(factor)` = 1.000000 ✓ +- `LogUniformPrior(0.01, 100)`: generic-path pdf integrates to **15.83**. + +Every `TransformedMessage`-wrapped prior (Uniform, LogUniform, LogGaussian) is +affected. `NormalMessage` / `TruncatedNormalMessage` priors are not. +`value_for`, `cdf`, `log_prior_from_value` and `factor` are all verified +correct — sampling and MCMC/MLE log-priors are unaffected; the exposure is +anything treating `transformed_message.pdf()` as a physical density. + +## Doc contradiction + +The `composed_transform.py` module docstring (added by #1334) claims `logpdf` +accumulates the log-Jacobian. The code does not. Either the docstring states +the intended contract (then `logpdf` needs the `log_det` term) or `logpdf` is +deliberately base-space for EP message arithmetic (then the docstring and +`pdf()` are misleading and should say so). + +## What adjudication needs + +1. Inventory callers of `TransformedMessage.logpdf`/`pdf` vs `factor` — + especially whether any EP projection / `log_norm` path evaluates `logpdf` + on transformed messages at physical coordinates. +2. `logpdf_gradient` returns the base `log_likelihood` with a + Jacobian-corrected *gradient* (value base-space, gradient physical) — a + third convention to settle in the same pass. +3. Decide: add `log_det` to the generic path, or document base-space `logpdf` + as the contract and fix the module docstring + `pdf()`. + +The #1497 property tests assert the physical density via `factor` and cite +#1498 at the site (`physical_log_density` helper in +`test_autofit/mapper/prior/test_prior_properties.py`); tighten them to +`logpdf` once resolved. + +## Sequencing + +Adjudicate alongside the parked single-source-density design (census C1/C4, +prompts `bug/priors/12`+`13`) — this is a fourth density-convention divergence +of exactly the kind that design exists to eliminate. The 12+13 design issue +should cite PyAutoFit#1498 as fresh evidence. diff --git a/draft/bug/priors/z_features.md b/draft/bug/priors/z_features.md index f2baf894..63b1605b 100644 --- a/draft/bug/priors/z_features.md +++ b/draft/bug/priors/z_features.md @@ -5,7 +5,19 @@ Target: priors Difficulty: too-large Autonomy: supervised Priority: normal -Status: formalised +Status: phases 1-3 SHIPPED; phase 4 = design (#1500) + parked 14 + finding 15 + +> **2026-08-18 wrap-up sweep.** All nine confirmed bugs (01-08, 10) are fixed +> and merged on PyAutoFit main — Phase 1 batch via #1344/PR#1345 (merged +> `c0b6c94b8`), Phase 2 width-modifier pair via #1346/PR#1348 (merged +> `cf0cc4bbb`), verified live 2026-07-14. All five decisions on hub #1331 are +> taken (see its 2026-07-14 resolution comment). Completion records: +> [[priors-messages-fixes]], [[prior-width-safety]], [[ep-priors-fable-reassess]]. +> Regression suites `test_priors_messages_fixes_1331.py` (12 tests) and +> `test_prior_width_safety.py` (11 tests) are on main. +> 2026-08-18 update: 09+11 SHIPPED (PR#1499 merged `21288bb`); 12+13 filed as +> design issue #1500 (decisions pending); 14 parked behind #1500; new finding +> 15 (#1498) awaiting adjudication. ## Why this folder exists @@ -62,12 +74,12 @@ Each can be filed independently and verified in minutes. | # | Prompt | Bug | Status | Issue | PR | |---|--------|-----|--------|-------|----| -| 01 | [log_gaussian_with_limits_crash](01_log_gaussian_with_limits_crash.md) | `LogGaussianPrior.with_limits` will `TypeError` on first call | pending | — | — | -| 02 | [uniform_logpdf_array_handling](02_uniform_logpdf_array_handling.md) | `UniformPrior.logpdf(np.array(...))` raises ambiguous-truth error | pending | — | — | -| 03 | [gamma_from_mode_wrong_formula](03_gamma_from_mode_wrong_formula.md) | `GammaMessage.from_mode` formula is dimensionally wrong | pending | — | — | -| 04 | [truncated_normal_log_partition_incomplete](04_truncated_normal_log_partition_incomplete.md) | `TruncatedNormalMessage` pdf does not integrate to 1 via generic interface | pending | — | — | -| 05 | [inv_beta_suffstats_clamp_noop](05_inv_beta_suffstats_clamp_noop.md) | `inv_beta_suffstats` negative-clamp branch is a no-op | pending | — | — | -| 06 | [normal_message_sigma_negative_unchecked](06_normal_message_sigma_negative_unchecked.md) | `NormalMessage` silently accepts negative sigma | pending | — | — | +| 01 | log_gaussian_with_limits_crash (prompt retired) | `LogGaussianPrior.with_limits` will `TypeError` on first call | **shipped 2026-07-10** | #1344 (hub #1331) | #1345 | +| 02 | uniform_logpdf_array_handling (prompt retired) | `UniformPrior.logpdf(np.array(...))` raises ambiguous-truth error | **shipped 2026-07-10** | #1344 (hub #1331) | #1345 | +| 03 | gamma_from_mode_wrong_formula (prompt retired) | `GammaMessage.from_mode` formula is dimensionally wrong | **shipped 2026-07-10** (D3: match mean+variance, α=m²/V) | #1344 (hub #1331) | #1345 | +| 04 | truncated_normal_log_partition_incomplete (prompt retired) | `TruncatedNormalMessage` pdf does not integrate to 1 via generic interface | **shipped 2026-07-10** (integral 2.27 → 1.0) | #1344 (hub #1331) | #1345 | +| 05 | inv_beta_suffstats_clamp_noop (prompt retired) | `inv_beta_suffstats` negative-clamp branch is a no-op | **shipped 2026-07-10** (D1: raises `ValueError`) | #1344 (hub #1331) | #1345 | +| 06 | normal_message_sigma_negative_unchecked (prompt retired) | `NormalMessage` silently accepts negative sigma | **shipped 2026-07-10** (D2: σ<0 rejected, σ=0 point-mass kept) | #1346 (hub #1331) | #1348 | ## Phase 2 — Convention / safety (require design input) @@ -77,14 +89,14 @@ expert to ratify the convention before code changes. | # | Prompt | Concern | Status | Issue | PR | |---|--------|---------|--------|-------|----| -| 07 | [log_prior_normalisation_convention](07_log_prior_normalisation_convention.md) | `log_prior_from_value` drops constants inconsistently across priors | pending | — | — | -| 08 | [relative_width_modifier_safety](08_relative_width_modifier_safety.md) | `RelativeWidthModifier` collapses to 0 / goes negative near zero means | pending | — | — | +| 07 | log_prior_normalisation_convention (prompt retired) | `log_prior_from_value` drops constants inconsistently across priors | **shipped 2026-07-10** (D4: Option A — drop constants everywhere + `Prior.log_normalisation()` hook) | #1344 (hub #1331) | #1345 | +| 08 | relative_width_modifier_safety (prompt retired) | `RelativeWidthModifier` collapses to 0 / goes negative near zero means | **shipped 2026-07-10** (D5: `abs(mean)` + opt-in `absolute_floor` + `PriorException` guard) | #1346 (hub #1331) | #1348 | ## Phase 3 — Testing infrastructure (would have caught everything above) | # | Prompt | Scope | Status | Issue | PR | |---|--------|-------|--------|-------|----| -| 09 | [prior_property_tests](09_prior_property_tests.md) | Add property-based correctness sweep over every `Prior` subclass | pending | — | — | +| 09 | prior_property_tests (→ complete/, [[prior-property-tests]]) | Add property-based correctness sweep over every `Prior` subclass | **SHIPPED 2026-08-18** (merged `21288bb`, 134 tests; folds in 11 §2) | #1497 | #1499 | ## Phase 4 — Refactors (only after Phases 1-3) @@ -94,11 +106,12 @@ over them. | # | Prompt | Scope | Status | Issue | PR | |---|--------|-------|--------|-------|----| -| 10 | [fixed_message_cache_growth](10_fixed_message_cache_growth.md) | `FixedMessage.logpdf_cache` is an unbounded class-level dict | pending | — | — | -| 11 | [transformed_message_semantics_doc](11_transformed_message_semantics_doc.md) | `TransformedMessage` reversal convention is undocumented foot-gun | pending | — | — | -| 12 | [single_source_density_refactor](12_single_source_density_refactor.md) | Each density is encoded in three places (`value_for` / `logpdf` / `log_prior_from_value`) | pending | — | — | -| 13 | [collapse_prior_and_message](13_collapse_prior_and_message.md) | `Prior` and `Message` carry duplicated responsibility | pending | — | — | -| 14 | [replace_transform_stack_with_bijectors](14_replace_transform_stack_with_bijectors.md) | Replace hand-rolled `AbstractDensityTransform` with `tfp.bijectors` / `numpyro.transforms` | pending | — | — | +| 10 | fixed_message_cache_growth (prompt retired) | `FixedMessage.logpdf_cache` is an unbounded class-level dict | **shipped 2026-07-10** (cache removed, aliasing fixed) | #1344 (hub #1331) | #1345 | +| 11 | transformed_message_semantics_doc (→ complete/, [[transformed-message-semantics-doc]]) | `TransformedMessage` reversal convention is undocumented foot-gun | **SHIPPED** — §1 via #1333/PR#1334 (2026-07-10), §2 via PR#1499 (2026-08-18) | #1333, #1497 | #1334, #1499 | +| 12 | single_source_density_refactor (→ active/) | Each density is encoded in three places (`value_for` / `logpdf` / `log_prior_from_value`) | **design issue FILED 2026-08-18** (bundled with 13) | #1500 | — | +| 13 | collapse_prior_and_message (→ active/) | `Prior` and `Message` carry duplicated responsibility | **design issue FILED 2026-08-18** (bundled with 12) | #1500 | — | +| 14 | [replace_transform_stack_with_bijectors](14_replace_transform_stack_with_bijectors.md) | Replace hand-rolled `AbstractDensityTransform` with `tfp.bijectors` / `numpyro.transforms` | parked — go/no-go hangs off the #1500 design decision | — | — | +| 15 | [transformed_message_logpdf_jacobian](15_transformed_message_logpdf_jacobian.md) | `TransformedMessage.logpdf`/`pdf` omit the transform Jacobian (new finding from the 09 sweep) | **issue filed 2026-08-18** — awaiting contract adjudication (standalone or inside #1500) | #1498 | — | --- diff --git a/draft/research/autofit/priors_and_messages_math_audit.md b/draft/research/autofit/priors_and_messages_math_audit.md index 11d7f69a..ce4292d3 100644 --- a/draft/research/autofit/priors_and_messages_math_audit.md +++ b/draft/research/autofit/priors_and_messages_math_audit.md @@ -5,7 +5,37 @@ Target: PyAutoFit Difficulty: too-large Autonomy: supervised Priority: high -Status: formalised +Status: RETIRED — historical record (2026-08-18); all 9 A-findings shipped, C-findings tracked in bug/priors/09,11-14 + +> **2026-08-18 wrap-up.** This census's actionable content has fully +> graduated; nothing here is left to action from this file. Outcome map: +> +> - **A1-A9 (all nine confirmed bugs): FIXED on PyAutoFit main.** Batch 1 +> (A1, A2, A3, A4, A5, A8) via #1344/PR#1345 (merged `c0b6c94b8`, +> 2026-07-10); batch 2 (A6, A9) via #1346/PR#1348 (merged `cf0cc4bbb`, +> 2026-07-10); A7 vectorised in PR#1345. All five open decisions were +> resolved on hub #1331 (see its 2026-07-14 comment): Beta clamp → raise; +> σ<0 rejected / σ=0 kept; Gamma `from_mode` matches mean+variance; +> normalisation → Option A (drop constants + `Prior.log_normalisation()` +> hook); width modifier → `abs(mean)` + opt-in floor + `PriorException`. +> Regression suites `test_priors_messages_fixes_1331.py` and +> `test_prior_width_safety.py` lock the fixes in. Completion records: +> [[priors-messages-fixes]], [[prior-width-safety]], +> [[ep-priors-fable-reassess]]. +> - **C-findings:** C2 shipped with the A5 decision (PR#1345). C6's +> reversal-convention half shipped via #1333/PR#1334 (EP review Phase 2); +> its `LinearShiftTransform` half shipped 2026-08-18 via PR#1499 +> ([[transformed-message-semantics-doc]]). C3 shipped 2026-08-18 as the +> property sweep, PR#1499 merged `21288bb` ([[prior-property-tests]]). +> C1+C4 are the live design issue PyAutoFit#1500. C5 remains as +> `bug/priors/14` (go/no-go behind #1500). C7 shipped as the A9/D5 fix. +> New 2026-08-18 finding from the sweep: PyAutoFit#1498 / +> `bug/priors/15` (TransformedMessage.logpdf omits the Jacobian). +> - GitHub hubs #1330/#1331 stay open only as the index for the parked +> design items above. +> +> Live tracking is `draft/bug/priors/z_features.md`; this file is kept as +> the historical audit record only. > **Fable re-validation (2026-07-08, main @ `0f26ff2d8`, PyAutoFit#1330):** > all nine A-findings reproduce on clean main — none aged out. Per-finding diff --git a/parked.md b/parked.md index 8b6df409..9210aead 100644 --- a/parked.md +++ b/parked.md @@ -6,6 +6,28 @@ unindexed worktrees or stashes. Move an entry back to `active.md` (or to `planned.md` if re-scoping is needed) when work resumes; on shipping, write the dated `complete///.md` record instead. +## single-source-density-design +- issue: https://github.com/PyAutoLabs/PyAutoFit/issues/1500 (open — the parked design hub) +- prompt: active/12_single_source_density_refactor.md +- parked: 2026-08-18 — **human-confirmed deferral** of the design decision (census wrap-up chat). + The bundled 12+13 design issue is filed with full evidence and four decision asks + (one-hierarchy-vs-two, #1498 logpdf contract, EP-mixin scope, prompt-14 sequencing); nothing is + blocked by deferring — bugs are fixed and the #1497/#1499 property sweep (134 tests, merged + `21288bb`) guards current behaviour regardless. +- classification: refactor design (PyAutoFit); DESIGN ONLY — no code until #1500 is answered. +- resume: answer the decisions on #1500, move this back to active.md, cut stage-1 as its own task + (Distribution sibling layer, Gaussian family first, property tests as the safety net). +- note: bug/priors/15 (#1498 — TransformedMessage.logpdf missing Jacobian) is a LIVE wrong answer, + not part of this deferral; it can be fixed standalone once the contract is picked. +- repos-none-claimed: claims no repos while parked. + +## prior-message-collapse-design +- issue: https://github.com/PyAutoLabs/PyAutoFit/issues/1500 (shared — bundled with single-source-density-design) +- prompt: active/13_collapse_prior_and_message.md +- parked: 2026-08-18 — same human-confirmed deferral; prompt 13 is the hierarchy-collapse half of + the #1500 bundle. Resume and retire together with single-source-density-design. +- repos-none-claimed: claims no repos while parked. + ## pyautoreduce-slacs1430-acs-comparison - prompt: active/pyautoreduce_slacs1430_acs_comparison.md - parked: 2026-08-08 — surfaced by the orphaned-prompt triage; STATE UNVERIFIED