You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Drafted by an LLM-based AI tool (Claude Code/Opus 5).
Summary
pm.compute_log_prior and pm.compute_log_likelihood both refuse to run on any model containing a pm.LKJCorr random variable, because they match the trace's posterior variables against the model's transformed value variable names while the posterior (correctly) stores the constrained name. The mismatch is a naming seam, not an intractable density.
Today this costs exactly one fit — lrp-rlm-jc-001 is the only model that both uses LKJCorr and routes through the standard compute_log_* path — so it is the last outstanding item on #381's psense coverage after #452 (192 of 194 fits covered; lrp-rlm-mm-001 is the other, and is a genuine non-converged exemption). But it will bite any future LKJCorr model on the standard path, and #383 recommends moving more models to LKJCorr, so the seam is worth closing before it spreads.
LKJCorr's default transform is a Cholesky-corr transform, so the value variable is <name>_cholesky_corr__. The posterior group stores the constrained draw under <name>. compute_log_prior derives the name it expects from the transform and finds no match:
exact match required for all data variable names, but
['eta_cell', 'sigma_subject', 'measure_corr_chol_cholesky', 'z_subject', 'kappa'] !=
['eta_cell', 'sigma_subject', 'kappa', 'measure_corr_chol', 'z_subject']
{'measure_corr_chol_cholesky', 'measure_corr_chol'} are not in both.
Observed on a real --config reporting fit of lrp-rlm-jc-001 on 2026-07-26. Both groups fail — the prior group as well as the likelihood group — so this is not the "likelihood is not evaluable" case that compute_log_likelihood_and_prior(strict=False) was written for. That argument lets the fit survive the failure; it does not repair it.
Why only one model is affected today
pm.LKJCorr appears three times in factories.py:
Line
RV
Model(s)
Affected?
5641
trait_corr_chol
lcf (longitudinal correlated-factor)
No
5646
state_corr_chol_w{n}
lcf
No
6319
measure_corr_chol
rlm-jc-001 (historical joint)
Yes
lcf escapes because it builds its log_likelihood / log_prior groups by a bespoke path rather than calling compute_log_likelihood_and_prior — a design already documented in that function's docstring ("Families with a bespoke log-likelihood … build their groups their own way and do not call this"), and confirmed by lrp-rli-lcf-001's stored trace carrying both groups and a valid psense_summary.csv. fit_rlm_joint_growth is compute_loo=False, so the sampling stage attaches nothing and it must request the groups explicitly — which is where it meets the seam.
Note the choice of LKJCorr here is deliberate and should not be reverted: factories.py:6315-6318 records that LKJCholeskyCov was rejected in this correlation-only role because its unused per-outcome sd scales are unidentified nuisances that pollute the all-free-RV convergence gate. #383 makes the same argument for switching mm / rlm-mmtoLKJCorr, which is precisely why this seam should be fixed rather than worked around by going back.
Options
Give historical_joint a bespoke log-prior path, as lcf already has. Most tractable, has in-repo precedent, and touches one family. Downside: a second bespoke path to maintain, and it does not help the next LKJCorr model.
Reconcile the name at the compute_log_* seam — pass the constrained-to-value mapping (model.rvs_to_values) or rename the trace variables into a throwaway copy before the call. Fixes every present and future LKJCorr model in one place. Needs care that the values passed are on the scale the log-density expects, which is the substantive risk: a silently wrong scale would produce plausible numbers rather than an error.
Check whether a newer PyMC resolves it upstream before building anything. Worth ten minutes first — if it is fixed above 6.1, this becomes a version bump plus a regression test.
Option 3 first, then 2 if the seam is ours to close, with 1 as the fallback.
Acceptance criteria
Root cause confirmed as ours or upstream, with the PyMC version behaviour recorded.
If the fix is at the seam (option 2), a test asserts that a model containing an LKJCorr RV can have compute_log_prior run against its own posterior — the naming contract, pinned so a PyMC upgrade cannot silently reintroduce it.
If the fix changes which values reach the log-density, the resulting psense numbers are sanity-checked against a model whose psense already works (lrp-rli-lcf-001 is the natural comparator — same LKJCorr construction, working groups).
ruff check src/, npm run format:check, npm run spellcheck pass.
Related
Found while closing #381's refit gap in #452, which added the psense wiring to fit_rlm_joint_growth that surfaced this — before that the artefacts were simply absent with no error at all. Connected to #383 (which would move more models onto LKJCorr) and to the general LKJCholeskyCov-vs-LKJCorr reasoning recorded at factories.py:6315-6318 and in notes/202607101638-mm-001-convergence-reparameterisation.md.
Note
Drafted by an LLM-based AI tool (Claude Code/Opus 5).
Summary
pm.compute_log_priorandpm.compute_log_likelihoodboth refuse to run on any model containing apm.LKJCorrrandom variable, because they match the trace's posterior variables against the model's transformed value variable names while the posterior (correctly) stores the constrained name. The mismatch is a naming seam, not an intractable density.Today this costs exactly one fit —
lrp-rlm-jc-001is the only model that both usesLKJCorrand routes through the standardcompute_log_*path — so it is the last outstanding item on #381's psense coverage after #452 (192 of 194 fits covered;lrp-rlm-mm-001is the other, and is a genuine non-converged exemption). But it will bite any futureLKJCorrmodel on the standard path, and #383 recommends moving more models toLKJCorr, so the seam is worth closing before it spreads.Reproduction
LKJCorr's default transform is a Cholesky-corr transform, so the value variable is<name>_cholesky_corr__. The posterior group stores the constrained draw under<name>.compute_log_priorderives the name it expects from the transform and finds no match:Observed on a real
--config reportingfit oflrp-rlm-jc-001on 2026-07-26. Both groups fail — the prior group as well as the likelihood group — so this is not the "likelihood is not evaluable" case thatcompute_log_likelihood_and_prior(strict=False)was written for. That argument lets the fit survive the failure; it does not repair it.Why only one model is affected today
pm.LKJCorrappears three times infactories.py:trait_corr_chollcf(longitudinal correlated-factor)state_corr_chol_w{n}lcfmeasure_corr_cholrlm-jc-001(historical joint)lcfescapes because it builds itslog_likelihood/log_priorgroups by a bespoke path rather than callingcompute_log_likelihood_and_prior— a design already documented in that function's docstring ("Families with a bespoke log-likelihood … build their groups their own way and do not call this"), and confirmed bylrp-rli-lcf-001's stored trace carrying both groups and a validpsense_summary.csv.fit_rlm_joint_growthiscompute_loo=False, so the sampling stage attaches nothing and it must request the groups explicitly — which is where it meets the seam.Note the choice of
LKJCorrhere is deliberate and should not be reverted:factories.py:6315-6318records thatLKJCholeskyCovwas rejected in this correlation-only role because its unused per-outcome sd scales are unidentified nuisances that pollute the all-free-RV convergence gate. #383 makes the same argument for switchingmm/rlm-mmtoLKJCorr, which is precisely why this seam should be fixed rather than worked around by going back.Options
historical_jointa bespoke log-prior path, aslcfalready has. Most tractable, has in-repo precedent, and touches one family. Downside: a second bespoke path to maintain, and it does not help the nextLKJCorrmodel.compute_log_*seam — pass the constrained-to-value mapping (model.rvs_to_values) or rename the trace variables into a throwaway copy before the call. Fixes every present and futureLKJCorrmodel in one place. Needs care that the values passed are on the scale the log-density expects, which is the substantive risk: a silently wrong scale would produce plausible numbers rather than an error.Option 3 first, then 2 if the seam is ours to close, with 1 as the fallback.
Acceptance criteria
lrp-rlm-jc-001emitspsense_summary.csvandpsense.pngat--config reporting, or the model is recorded as a documented exemption with the specific reason (matching the treatmentlrp-rlm-mm-001already gets under Emit power-scaling (psense) and prior-pushforward artifacts for all estimand-reporting families #381), not left silently absent.LKJCorrRV can havecompute_log_priorrun against its own posterior — the naming contract, pinned so a PyMC upgrade cannot silently reintroduce it.psensenumbers are sanity-checked against a model whose psense already works (lrp-rli-lcf-001is the natural comparator — sameLKJCorrconstruction, working groups).notes/202607261700-psense-coverage-backfill.mdupdated with the outcome; Emit power-scaling (psense) and prior-pushforward artifacts for all estimand-reporting families #381's coverage line moves from 192/194.ruff check src/,npm run format:check,npm run spellcheckpass.Related
Found while closing #381's refit gap in #452, which added the
psensewiring tofit_rlm_joint_growththat surfaced this — before that the artefacts were simply absent with no error at all. Connected to #383 (which would move more models ontoLKJCorr) and to the generalLKJCholeskyCov-vs-LKJCorrreasoning recorded atfactories.py:6315-6318and innotes/202607101638-mm-001-convergence-reparameterisation.md.