Skip to content

feature: hBayesDM version 2.0#182

Merged
bugoverdose merged 35 commits into
CCS-Lab:developfrom
Nathaniel-Haines:feature-cmdstan-version-2.0
May 20, 2026
Merged

feature: hBayesDM version 2.0#182
bugoverdose merged 35 commits into
CCS-Lab:developfrom
Nathaniel-Haines:feature-cmdstan-version-2.0

Conversation

@Nathaniel-Haines
Copy link
Copy Markdown
Member

@Nathaniel-Haines Nathaniel-Haines commented May 5, 2026

hBayesDM 2.0 — modernize stack & toolchain

Top-to-bottom refactor of both the R and Python packages onto
current Stan tooling, plus the supporting work to keep behavior, docs, and
CI in sync.

Highlights

  • Stan backend: rstan → cmdstanr (R) and pystan →
    cmdstanpy (Python). CmdStan is now a system dependency installed once via cmdstanr::install_cmdstan() / cmdstanpy.install_cmdstan(). No install-time precompilation; models compile on first use (~30 s) and the binary is cached.
  • Languages: R ≥ 4.4, Python ≥ 3.13.
  • Python tooling: poetry → uv + hatchling (Python/pyproject.toml).
  • Stan files: canonicalized (array[N, T] real x, abs
    for fabs) across all 66 models.
  • arviz updated to the post-1.0 API (DataTree, plot_dist, ci_prob, LOO-only extract_ic).

Breaking changes

  • result$fit (R) / model.fit (Python) is now a CmdStanMCMC/CmdStanVB object, not rstan::stanfit. Replace rstan::extract(fit) with posterior::as_draws_*(fit$draws()) or use the already-extracted parVals/par_vals.
  • BUILD_ALL=true install-time precompile flag removed.
  • Python now requires 3.13+; R requires 4.4+.

Latent bugs fixed (no test previously)

  • R additional_args: args[[nm]] <- NULL was deleting entries with NULL defaults (e.g. banditNarm_2par_lapse Narm, pstRT_ddm initQ). Switched to args[nm] <- list(NULL) so the entry is preserved.
  • R rhat(): name collision with posterior::rhat caused cmdstanr's $summary("rhat", ...) to recurse into hBayesDM's own rhat. Now binds posterior::rhat to a local symbol and passes by value.
  • Python vb=True: dict inits were being passed to cmdstanpy.variational(), which only accepts Optional[float]. Inits are now dropped on the VB branch.
  • Python VB idata: was using stan_variables()
    (variational means) and producing 1-D arrays. Now uses stan_variables(mean=False) for the variational sample matrix.

Tests

  • New tests/test_user_facing.{py,R} — fits one small model (dd_hyperbolic) and exercises plotting (dist/trace/simple), plot_ind, rhat, extract_ic, print_fit, HDI helpers, plus gng_m1 for model_regressor and dd_hyperbolic(vb=TRUE) for the VB path.
  • Per-model smoke tests under tests/test_<model>.{py,R} unchanged.
  • All 15 Python + 42 R user-facing tests pass.

Docs

  • R/man-roxygen/model-documentation.Rfit description updated to CmdStanMCMC/CmdStanVB; first-fit compile note added. All 68 R/man/*.Rd regenerated via roxygen2.
  • R/README.Rmd, Python/README.rst, top-level README.md — install instructions, prerequisites, Python/R version requirements.
  • R/NEWS.md — 2.0 entry with breaking changes and migration snippets.
  • R/vignettes/getting_started.Rmd — full pass: install steps, fitting walkthrough, console output, post-fit object description, Section 3 plotting rewritten around bayesplot, Section 6 VB pointing at cmdstanr.
  • R/vignettes/hgf_tutorial.Rmd — link fix.
  • R/cran-comments.md — refreshed for 2.0 submission story.
  • Python/docs/{requirements.txt,conf.py} and .readthedocs.yml — bumped to Python 3.13 + arviz ≥ 0.20.

CI/CD

  • Removed: .travis.yml and travis/ (xenial, Python 3.6–3.8, poetry, unmaintained). Travis ran R CMD check --no-tests and only one Python test.
  • Added .github/workflows/R.yaml — Ubuntu + Windows runners, R 4.4, cached CmdStan, R CMD check + test_user_facing.R, codecov upload.
  • Added .github/workflows/Python.yaml — Ubuntu + Windows runners, Python 3.13 via uv, cached CmdStan, ruff + test_user_facing.py + 2 representative model smoke tests.
  • Updated pkgdown.yaml — pinned R 4.4, installs cmdstanr so vignettes can re-render in CI.
  • README badges swapped from Travis to the two new GH Actions
    workflows.

Repo hygiene

  • New DEVELOPERS.md at repo root: layout, toolchain, conventions, gotchas (additional_args plumbing, the rhat name collision, VB inits / sample matrix), and the dev loop.
  • CONTRIBUTING.md added to explain how to add new model, etc

Test plan

  • cd Python && uv run pytest tests/test_user_facing.py (15/15 pass)
  • cd Python && uv run pytest tests/test_<model>.py (all pass)
  • NOT_CRAN=true Rscript -e 'testthat::test_file("R/tests/testthat/test_user_facing.R")' (42/42 pass)
  • NOT_CRAN=true Rscript -e 'testthat::test_file("R/tests/testthat/test_<model>.R")' (all pass)
  • R CMD INSTALL --no-docs --no-test-load R (clean)
  • roxygen2::roxygenize("R") regenerates man pages without errors
  • rmarkdown::render("R/vignettes/getting_started.Rmd") builds
  • rmarkdown::render("R/vignettes/hgf_tutorial.Rmd") builds
  • First push: confirm the new GH Actions workflows are green on a real run
  • comparison of fit results on master (rstan/hBayesDM 1.3.1) vs this branch (cmdstanr/2.0); see comment below

@Nathaniel-Haines
Copy link
Copy Markdown
Member Author

Nathaniel-Haines commented May 5, 2026

Behavioral equivalence: master (rstan/hBayesDM 1.3.1) vs this branch (cmdstanr/2.0)

To verify the cmdstan-2.0 port produces equivalent posteriors, I fit each shared model on both backends to the package example data with matched sampler settings (niter=500, nwarmup=250, nchain=6, ncore=6, seed=12345) and compared per-subject posterior mean & SD per parameter, plus model-level LOOIC.

Master was installed from the 1.3.1 release into a parallel R library path; per-subject summaries were extracted via rstan::extract (master) and posterior::draws_of (feature). LOOIC came from extract_ic(..., ic="looic") on both sides.

36 models paired successfully. Remaining models on master deterministically segfaulted inside rstan 2.32.x's QuickJS-based stanc on macOS arm64 (a known rstan/V8 issue, not a model bug). Coverage spans 15 task families: bandits (2/4/N-arm + lapse/decay/Kalman variants), DD (cs/exp/hyperbolic), RA (prospect/noLA/noRA), IGT (ORL/PVL-decay/PVL-delta), PRL (EWA/RP), PST (Q/gainloss-Q), CRA (exp/linear), UG (bayes/delta), BART, CGT, peer_ocu, task2AFC_sdt, alt_delta.

Across-model summary

LOOIC, master vs feature — error bars are LOO SE.

looic overall

All per-subject posterior means, pooled across models and parameters.

mean grand

All per-subject posterior SDs, pooled across models and parameters.

sd grand

Per-model parameter scatters

Each model gets a 2-row figure: top row = per-subject posterior mean (master x, feature y), faceted by parameter; bottom row = per-subject posterior SD, same layout. Identity line drawn for reference.

alt_delta

alt_delta

bandit2arm_delta

bandit2arm_delta

bandit4arm2_kalman_filter

bandit4arm2_kalman_filter

bandit4arm_2par_lapse

bandit4arm_2par_lapse

bandit4arm_4par

bandit4arm_4par

bandit4arm_lapse

bandit4arm_lapse

bandit4arm_lapse_decay

bandit4arm_lapse_decay

bandit4arm_singleA_lapse

bandit4arm_singleA_lapse

banditNarm_2par_lapse

banditNarm_2par_lapse

banditNarm_4par

banditNarm_4par

banditNarm_delta

banditNarm_delta

banditNarm_kalman_filter

banditNarm_kalman_filter

banditNarm_lapse

banditNarm_lapse

banditNarm_lapse_decay

banditNarm_lapse_decay

banditNarm_singleA_lapse

banditNarm_singleA_lapse

bart_par4

bart_par4

cgt_cm

cgt_cm

cra_exp

cra_exp

cra_linear

cra_linear

dd_cs

dd_cs

dd_exp

dd_exp

dd_hyperbolic

dd_hyperbolic

igt_orl

igt_orl

igt_pvl_decay

igt_pvl_decay

igt_pvl_delta

igt_pvl_delta

peer_ocu

peer_ocu

prl_ewa

prl_ewa

prl_rp

prl_rp

pst_Q

pst_Q

pst_gainloss_Q

pst_gainloss_Q

ra_noLA

ra_noLA

ra_noRA

ra_noRA

ra_prospect

ra_prospect

task2AFC_sdt

task2AFC_sdt

ug_bayes

ug_bayes

ug_delta

ug_delta

…version-2.0

# Conflicts:
#	Python/pyproject.toml
#	Python/setup.py
#	R/DESCRIPTION
@Nathaniel-Haines Nathaniel-Haines requested a review from youngahn May 5, 2026 18:34
@Nathaniel-Haines Nathaniel-Haines changed the title feature: cmdstan version 2.0 feature: hBayesDM version 2.0 May 5, 2026
Nathaniel-Haines and others added 4 commits May 5, 2026 14:45
R workflow also calls cmdstanr::check_cmdstan_toolchain(fix=TRUE) so the
RTools toolchain is set up before install_cmdstan(). Python install step
pinned to bash shell since the existing $CMDSTAN_VERSION expansion is bash
syntax.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The combined "tests + codecov" step was gated to ubuntu-only because
covr::codecov() needs the token. Split so non-ubuntu platforms still run
the tests under testthat::test_file(); ubuntu still wraps in covr for
coverage upload.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
R workflow now has three named steps after R CMD check:
  1. Install hBayesDM        — R CMD INSTALL on every platform
  2. Run user-facing tests   — testthat::test_file on every platform
  3. Upload coverage         — ubuntu only, runs covr-instrumented tests

Fixes Windows test failure where library(hBayesDM) couldn't find the
package (it lived only inside the temp library used by R CMD check).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@bugoverdose bugoverdose self-requested a review May 6, 2026 10:18
Comment on lines +67 to +78
lambda_pr ~ normal(0, 1);
;
theta_pr ~ normal(0, 1);
;
beta_pr ~ normal(0, 1);
;
mu0_pr ~ normal(0, 1);
;
s0_pr ~ normal(0, 1);
;
sD_pr ~ normal(0, 1);
;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since we are changing the code anyway, how about fixing this part?

Suggested change
lambda_pr ~ normal(0, 1);
;
theta_pr ~ normal(0, 1);
;
beta_pr ~ normal(0, 1);
;
mu0_pr ~ normal(0, 1);
;
s0_pr ~ normal(0, 1);
;
sD_pr ~ normal(0, 1);
;
lambda_pr ~ normal(0, 1);
theta_pr ~ normal(0, 1);
beta_pr ~ normal(0, 1);
mu0_pr ~ normal(0, 1);
s0_pr ~ normal(0, 1);
sD_pr ~ normal(0, 1);

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good catch, fixed!

Comment thread Python/docs/requirements.txt Outdated
Comment on lines 1 to 9
numpy>=2.1
scipy
pandas
matplotlib
pystan
arviz
pylint
flake8
pytest
pytest-rerunfailures
cmdstanpy>=1.2.5
arviz>=0.20
sphinx
sphinx-autodoc-typehints
sphinx-rtd-theme
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Considering that dependency compatibility might break in the future, how about specifying the versions instead of just using >=?

numpy==2.1.*
scipy
pandas
matplotlib
cmdstanpy==1.2.5
arviz==0.20.*
sphinx
sphinx-autodoc-typehints
sphinx-rtd-theme

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel there is a trade off with python in these cases:

  • pinning more strictly and it means hbayesdm will be harder for folks to install in their local envs (which may have strict dependencies that conflict with ours)
  • current setup with >= and you risk some breaking change introduced down the line

do you guys have a preference? an alternative would be something where we try to hedge against breaking changes by giving a range—e.g., cmdstanpy>=1.2.5,<2 (but this makes an assumption about when a breaking change may occur)

Copy link
Copy Markdown
Member

@bugoverdose bugoverdose May 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should choose between cmdstanpy>=1.2.5 and cmdstanpy>=1.2.5,<2.0.

I personally think giving a range is better than setting no upper bound, but I agree with your concern.

Please choose freely.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice, went with caps at the next major version, which in theory should be when breaking changes are expected to hit

Comment thread Python/pyproject.toml
"Programming Language :: Python :: 3.7",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3 :: Only"
"Programming Language :: Python :: 3.13",
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just out of curiosity, is there a special reason you chose Python 3.13 as the minimum required version?

If you simply wanted the highest version available, maybe we can try v3.14?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ha good q I thought about this for a bit.. honestly it was mostly a heuristic. e.g., looking at the version lifecycles, 3.13 is almost out of "bug fix" territory and into "security" territory. I figure it is likely stable enough that it won't cause issues

but happy either way! I think both would be fine

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for sharing. I didn't know about this site.

I agree with you. Let's go with 3.13.

image

Comment thread R/R/hBayesDM_model.R
Comment on lines +492 to +508
fit_result <- .hbayesdm_fit(
model_name = stan_model_name,
data_list = data_list,
pars = pars,
gen_init = gen_init,
vb = vb,
nchain = nchain,
niter = niter,
nwarmup = nwarmup,
nthin = nthin,
adapt_delta = adapt_delta,
stepsize = stepsize,
max_treedepth = max_treedepth,
ncore = ncore,
inc_postpred = inc_postpred,
postpreds = postpreds
)
Copy link
Copy Markdown
Member

@bugoverdose bugoverdose May 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are a few features that I've implemented in another PR that has not been merged yet. To reduce unnecessary git conflict, I think this PR should be merged first.

However, if you are interested, I want to ask your opinion about applying these changes to this PR based on this commit.

  • [Feature 1] setting seed for MCMC sampling for reproducibility
  • [Feature 2] setting all initial values to 0 by using inits=0 argument

(I was planning to create a PR from your feature-cmdstan-version-2.0 branch and implement them myself, but apparently the branch is in your forked repository so I couldn't do that.)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice both make sense to me! seed is good to have and the init=0 is often helpful IME with more complex models

I just cherry-picked your commits to bring them in 👍

Comment thread R/.tool-versions Outdated
@@ -0,0 +1 @@
R 4.4.1 No newline at end of file
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not mandatory, but I think you can consider adding trailing newline at the end of the file.

Suggested change
R 4.4.1
R 4.4.1

There's a small warning shown in github.
Image

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah oops, meant to keep this local, it is just something I use for local dev, removed

Comment thread .gitignore
Comment on lines +359 to +361
# compiled stan objects
commons/stan_files/*
!commons/stan_files/*.stan
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was so needed. Thank you.

Comment thread CONTRIBUTING.md
@@ -0,0 +1,280 @@
# Contributing to hBayesDM
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you applied some kind of lint (code formatter) for all the previous Stan code. How about mentioning it in this page?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah actually I updated it using cmdstan:

for f in commons/stan_files/*.stan; do                         
    ~/.cmdstan/cmdstan-*/bin/stanc --print-canonical
    --canonicalize=deprecations "$f" > "$f.new" && mv "$f.new" "$f"
done  

just added a bit in DEVELOPERS.md to make this strategy clear

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TBC—above is not linting per se, but updating old to new model syntax

@Nathaniel-Haines
Copy link
Copy Markdown
Member Author

Nathaniel-Haines commented May 7, 2026

@bugoverdose @youngahn any thoughts on next steps/a plan for merging this in? Or any further tests you'd like to see?

Happy to sync up over a video chat if it would be helpful first, just let me know!

@bugoverdose
Copy link
Copy Markdown
Member

Let's keep the comments unresolved so that other people can easily read it and catch up easily.

Comment thread Python/hbayesdm/models/_pst_Q.py Outdated
Copy link
Copy Markdown
Member

@bugoverdose bugoverdose May 14, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is the part @Leonardo-DongCaprio mentioned regarding the syntax issue.

Full warning message: SyntaxWarning: "\%" is an invalid escape sequence. Did you mean "\\%"?

Affected files:

  • hbayesdm/models/_pst_Q.py
  • hbayesdm/models/_pst_gainloss_Q.py
  • hbayesdm/models/_ra_noLA.py
  • hbayesdm/models/_ra_noRA.py
  • hbayesdm/models/_ra_prospect.py
  • hbayesdm/models/_rdt_happiness.p
  • ...

This doesn't have to do with the changes in the PR, but I guess you can change it now if you want?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so the issue here is the escape character behavior in R vs Python—added a step that corrects this on Python side and tested that the warnings no longer surface

@Leonardo-DongCaprio
Copy link
Copy Markdown

Leonardo-DongCaprio commented May 14, 2026

I tested PR #182 locally on macOS.

uv sync --all-groups completed successfully, and I confirmed that hbayesdm can be imported correctly inside the uv environment.

The documented smoke test command:

uv run pytest tests/test_ra_prospect.py -x

failed on my machine with:

ModuleNotFoundError: No module named 'hbayesdm'

However, running pytest through Python directly worked:

uv run python -m pytest tests/test_ra_prospect.py -x

Result:

tests/test_ra_prospect.py . [100%]
1 passed, 6 warnings in 13.64s

So the Python ra_prospect smoke test passed locally when using:

uv run python -m pytest tests/test_ra_prospect.py -x

I also saw six SyntaxWarning messages related to invalid escape sequences such as "\%" in model docstrings. These do not break the test, but may be worth cleaning up.

@Leonardo-DongCaprio
Copy link
Copy Markdown

I also tested the R-side smoke test locally on macOS.

Command used:

Rscript -e 'testthat::test_file("tests/testthat/test_ra_prospect.R")'

Result:

══ Testing test_ra_prospect.R ═════════════════════════════════════════════════════════════════
[ FAIL 0 | WARN 0 | SKIP 1 | PASS 0 ]

── Skipped tests (1) ──────────────────────────────────────────────────────────────────────────
• On CRAN (1): test_ra_prospect.R:6:3

So the R-side test file did not fail locally, but the only test was skipped because it appears to be guarded by an On CRAN / skip_on_cran() condition.

I also saw the following non-critical warning:

Warning message:
package ‘testthat’ was built under R version 4.5.2

Overall, the R smoke test command ran successfully, and there were no test failures. However, the actual test body was skipped due to the CRAN-skip condition.

@Leonardo-DongCaprio
Copy link
Copy Markdown

Leonardo-DongCaprio commented May 14, 2026

I also ran the R test with NOT_CRAN=true:

NOT_CRAN=true Rscript -e 'testthat::test_file("tests/testthat/test_ra_prospect.R")'

Result:
[ FAIL 0 | WARN 0 | SKIP 0 | PASS 1 ] Done!

@Leonardo-DongCaprio
Copy link
Copy Markdown

I also ran an additional Python model test locally on macOS.

Command:

uv run python -m pytest tests/test_dd_hyperbolic.py -x

Result:

tests/test_dd_hyperbolic.py . [100%]
1 passed in 11.39s

So, in addition to the ra_prospect Python smoke test, the dd_hyperbolic Python test also passed locally when run through:

uv run python -m pytest ...

@Leonardo-DongCaprio
Copy link
Copy Markdown

I also reviewed the updated documentation around the backend migration.

The R-side documentation looks clear to me:

  • R/NEWS.md explicitly describes the hBayesDM 2.0.0 development refactor as a breaking change.
  • It documents the backend migration from rstan to cmdstanr.
  • It explains that the result object's fit slot is now CmdStanMCMC / CmdStanVB rather than rstan::stanfit.
  • It also provides migration examples using output$fit$draws(), posterior::as_draws_df(), and output$parVals.

The R README also clearly documents the new prerequisites:

  • R ≥ 4.4
  • cmdstanr
  • one-time CmdStan installation via cmdstanr::install_cmdstan()
  • first-use Stan model compilation and caching.

The Python README also documents the major changes clearly:

  • Python ≥ 3.13
  • cmdstanpy backend
  • one-time CmdStan installation via cmdstanpy.install_cmdstan()
  • first-use Stan model compilation and caching.

Overall, the main R/Python README and NEWS documentation seem aligned with the backend migration. The only issue I noticed so far is the quickstart smoke-test command I mentioned earlier, where uv run pytest ... failed on my macOS setup but uv run python -m pytest ... worked.

@Nathaniel-Haines
Copy link
Copy Markdown
Member Author

I tested PR #182 locally on macOS.

uv sync --all-groups completed successfully, and I confirmed that hbayesdm can be imported correctly inside the uv environment.

The documented smoke test command:

uv run pytest tests/test_ra_prospect.py -x

failed on my machine with:

ModuleNotFoundError: No module named 'hbayesdm'

However, running pytest through Python directly worked:

uv run python -m pytest tests/test_ra_prospect.py -x

Result:

tests/test_ra_prospect.py . [100%]
1 passed, 6 warnings in 13.64s

So the Python ra_prospect smoke test passed locally when using:

uv run python -m pytest tests/test_ra_prospect.py -x

I also saw six SyntaxWarning messages related to invalid escape sequences such as "\%" in model docstrings. These do not break the test, but may be worth cleaning up.

@Leonardo-DongCaprio I was only able to re-create this error locally by uninstalling hbayesdm and then trying to run pytest. I wonder if this is something about your local dev that is pointing to the wrong pytest? e.g., what happens when you run: uv run which pytest—does this point to the local project installation of pytest or to some system installation instead? I am guess the latter?

In either case, I have updated the CONTROBUTORS.md with exact steps I follow locally that produces behavior without needing the python run -m pytest part. If you follow that flow and still run into the error, let me know and I can dig deeper/update docs to recommend your approach

@Nathaniel-Haines
Copy link
Copy Markdown
Member Author

I also tested the R-side smoke test locally on macOS.

Command used:

Rscript -e 'testthat::test_file("tests/testthat/test_ra_prospect.R")'

Result:

══ Testing test_ra_prospect.R ═════════════════════════════════════════════════════════════════
[ FAIL 0 | WARN 0 | SKIP 1 | PASS 0 ]

── Skipped tests (1) ──────────────────────────────────────────────────────────────────────────
• On CRAN (1): test_ra_prospect.R:6:3

So the R-side test file did not fail locally, but the only test was skipped because it appears to be guarded by an On CRAN / skip_on_cran() condition.

I also saw the following non-critical warning:

Warning message:
package ‘testthat’ was built under R version 4.5.2

Overall, the R smoke test command ran successfully, and there were no test failures. However, the actual test body was skipped due to the CRAN-skip condition.

@Leonardo-DongCaprio so I believe this is the behavior we want, and it is consistent with the state of the repo before my changes here. To run these you need the NOT_CRAN=true flag before the test. IN CI/CD we skip the every-model smoke tests but run some select examples to test that the the pipelines generally work

(also see your recent comment that tests work with the flag, nice!)

@Nathaniel-Haines
Copy link
Copy Markdown
Member Author

I also reviewed the updated documentation around the backend migration.

The R-side documentation looks clear to me:

  • R/NEWS.md explicitly describes the hBayesDM 2.0.0 development refactor as a breaking change.
  • It documents the backend migration from rstan to cmdstanr.
  • It explains that the result object's fit slot is now CmdStanMCMC / CmdStanVB rather than rstan::stanfit.
  • It also provides migration examples using output$fit$draws(), posterior::as_draws_df(), and output$parVals.

The R README also clearly documents the new prerequisites:

  • R ≥ 4.4
  • cmdstanr
  • one-time CmdStan installation via cmdstanr::install_cmdstan()
  • first-use Stan model compilation and caching.

The Python README also documents the major changes clearly:

  • Python ≥ 3.13
  • cmdstanpy backend
  • one-time CmdStan installation via cmdstanpy.install_cmdstan()
  • first-use Stan model compilation and caching.

Overall, the main R/Python README and NEWS documentation seem aligned with the backend migration. The only issue I noticed so far is the quickstart smoke-test command I mentioned earlier, where uv run pytest ... failed on my macOS setup but uv run python -m pytest ... worked.

@Leonardo-DongCaprio thanks for looking over docs in depth and for testing!

I responded to other comments above, but re the quickstart issue, I realized there was some drift between the quickstart guide and the DEVELOPERS.md, so I just added the quickstart to the latter doc in an effort to minimize drift. Curious your response to this comment, as I was not able to reproduce the pytest/install issue you hit before 🤔

@Nathaniel-Haines
Copy link
Copy Markdown
Member Author

@bugoverdose @Leonardo-DongCaprio @youngahn so I believe I have addressed all comments, although we should nail down this before merging. I believe it may just be a local dev setup issue, but ofc if it is surfacing here then that suggests some hole in the docs. Problem is I cannot reproduce locally so it is hard for me to "fix"

@bugoverdose
Copy link
Copy Markdown
Member

@Nathaniel-Haines How about merging it on 5/20(Wed)?

More people in our lab could leave additional comments so I think it can be better to give just a few more days. Would that be OK for you?

@Nathaniel-Haines
Copy link
Copy Markdown
Member Author

@bugoverdose that works for me! No rush from my side so take your time

Comment thread Python/hbayesdm/diagnostics.py Outdated

def plot_hdi(x: np.ndarray,
credible_interval: float = 0.94,
prob: float = 0.94,
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a minor thing, but is there a reason plot_hdi uses the argument name prob while plot and plot_ind use ci_prob? I think this inconsistency can be slightly confusing.

Copy link
Copy Markdown
Member Author

@Nathaniel-Haines Nathaniel-Haines May 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good point @comicvalentine, I agree and think we should just standardize all to ci_prob, here is a full list of changes we would need (minus tests and docs):

  • Python/hbayesdm/diagnostics.pyhdi() and
    plot_hdi(): renamed prob → ci_prob; also should change the default 0.94 → 0.95 (default is currently different between R and Python?).
  • Python/hbayesdm/base.pyTaskModel.plot() and
    TaskModel.plot_ind(): default ci_prob 0.94 → 0.95 (name is
    already ci_prob).
  • R/R/HDIofMCMC.R — arg credMass → ciProb; default
    0.95 unchanged.
  • R/R/plotHDI.R — arg credMass → ciProb;
    default 0.95 unchanged.

but this begs a bigger question IMO—should we take this opportunity to also standardize some of the other deviations across R and Python (as well as within R)? For example, all the R functions are camelCase (as are most arg names, although some functions mix cases which is confusing), whereas Python are snake_case.

Because modern tidyverse is all snake_case, I think we would benefit from taking the 2.0 update to standardize all the R functions + args to snake_case. e.g., plotHDI → plot_hdi, etc. @youngahn @bugoverdose @Leonardo-DongCaprio any strong opinions against this? I know it would be a breaking change, but I think it is a worthwhile one to make the R and Python APIs more consistent, and to modernize the R side a bit more too. We could make these change very clear in the NEWS.md and release docs, of course

Copy link
Copy Markdown

@comicvalentine comicvalentine May 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My very personal concern would be the migration cost for existing R users, especially if many existing scripts/notebooks would need to be updated at once to get the benefits of CmdStan. As I briefly checked in the current commit, the plotting argument renames in Python (credible_intervalci_prob / prob) seemed to be the only user-facing API changes affecting existing code, so a broader R/Python naming standardization (particularly camelCase → snake_case) feels like a much larger breaking change in comparison.
But I agree that, in the long run, the modernization and standardization would be beneficial overall — so it probably comes down to the maintainers’ preference/priorities.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah it is a tough call.. my thinking is generally that if we don't make the change now, the next opportunity would be a 3.0 release (whatever and whenever that may be), and we will have the same concern at that point—so if we think it is a change worth making at some point, I think now is the time (otherwise I say we just stick with the variance)

Copy link
Copy Markdown
Member

@bugoverdose bugoverdose left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@youngahn
Copy link
Copy Markdown
Member

Yes, it's a tough call for me, too...

camelCase → snake_case is a big change, but how about make the change in 2.0?

@Nathaniel-Haines
Copy link
Copy Markdown
Member Author

Yes, it's a tough call for me, too...

camelCase → snake_case is a big change, but how about make the change in 2.0?

I think it will make us happy in the future! We will just need to be very clear about the change in the release

I imagine for most users, this will only impact them on a go-forward basis. For older scripts, they will still work so long as they have library versions pinned (and if they don't... well that is partly on them)

@Nathaniel-Haines
Copy link
Copy Markdown
Member Author

@youngahn @bugoverdose @Leonardo-DongCaprio OK I implemented the camelCase -> snake_case sweep, double checked + re-rendered docs + vignettes, and ran some model smoke tests locally (in addition to what CI/CD runs automatically). I also added an entry to NEWS.md outlining the changes.

Feel free to merge this whenever! Or alternatively let me know if there are any remaining concerns I can address 🤓

@bugoverdose bugoverdose merged commit 6a637a8 into CCS-Lab:develop May 20, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants