New Session menu in the header, next to the theme toggle, to save the
current work to a .rds file and load it back from any tab. Loading
restores the priors, the expert pool, the MAP prior and the report
details. Conflict, sensitivity and robust / power results are saved in the
file but are not restored; rerun them after loading. Session files are
validated on load (format, version, expected contents and size).
Export Report: new Export R script button that writes a script reproducing the analysis (elicitation inputs, expert pooling, MAP prior, robust, sceptical and power priors, prior-data conflict and sensitivity analyses). Steps that cannot be written as code are included as comments.
Export Report: required fields are marked, a readiness checklist shows what is still missing, and the action buttons are restyled for light and dark mode.
Roulette: a fitted prior now also becomes the base prior, so Sensitivity and the robust / power pages use it.
Conflict Diagnostics no longer fails when no result is produced.
prior_conflict() now computes box_pvalue (and the s_value derived
from it) from the exact prior predictive distribution by default
wherever a closed form exists: Beta-Binomial (Beta prior, type = "binary") and Gamma-Poisson / Negative Binomial (Gamma prior, type = "poisson" or "survival"). The exact argument now defaults to NULL
(exact where available, silent fallback to the Normal approximation
otherwise); exact = TRUE additionally messages on fallback and
exact = FALSE reproduces the Normal-approximation results of 0.4.0 and
earlier. The exact check requires whole-number counts (and, for binary
data, a whole-number sample size); otherwise the Normal approximation is
used. $box_pvalue_method reports which was used.
Reason: a simulation study (see validation/) found that the Normal
approximation, whose standard error is estimated from the observed
proportion or count, can reject far more often than its nominal level when
there is no prior-data conflict, for informative priors and small samples.
For example, for a Beta(5, 45) prior with n = 10 and no conflict, the
approximation flagged conflict in about 39% of simulated datasets at the
5% level, because zero observed events (probable under the prior) yield a
zero standard error and a small approximate p-value. The exact version's
rejection rate stayed at or below the nominal level in all simulated
settings. Results for moderate samples and weakly informative priors are
essentially unchanged.
The prior predictive p-value now also covers mixture priors (e.g.
robust_prior(), and linear pooling from aggregate_experts()): the
predictive is the weighted mixture of the component predictives, exact for
Beta (binary) or Gamma (Poisson/survival) components. Other proper priors
(Normal, lognormal, Weibull, exponential, or a Normal vague component) are
handled by equal-probability quadrature over the prior, truncated to the
parameter space; $box_pvalue_method is then "numerical". The
definition of the p-value is the same throughout (total predictive
probability of outcomes no more probable than the observed one). In the
simulation (validation/sim_mixture.R), pooled-consensus mixtures with
the Normal approximation rejected up to 43% of the time at the 5% level
under no conflict; the prior predictive version never exceeded 5%. For
lognormal, Weibull and exponential priors on a rate (validation/ sim_numerical.R, 84 cells) the numerical p-value never exceeded the
nominal level either (the approximation reached 63%). At equal size, the
prior predictive p-value has the same average power as the old
approximation, but less power against downward shifts for skewed priors
(validation/sim_power.R; see REPORT_boxp.md for the full comparison).
New field $box_pvalue_caution on prior_conflict() results: set when
the Normal approximation produced the p-value for discrete data with zero
or all events, or fewer than 10 events or non-events. Shown in print()
and in the app.
conflict_severity is now classified on the reported box_pvalue:
"severe" below 2 * pnorm(-3) (about 0.0027), "mild" below alpha.
This equals the earlier rule (surprise_index >= 3) whenever the Normal
approximation is used, and avoids mixing an exact p-value with an
approximate distance otherwise.
Shiny app (Conflict module): the "exact prior predictive" option is now on by default; unchecking it uses the Normal approximation throughout.
plot_sensitivity() and plot_tornado() gain an interactive argument.
The default (FALSE) returns a ggplot object exactly as before;
interactive = TRUE returns a plotly object with readable tooltips
(rounded values and parameter labels instead of raw column names) and, for
the tornado plot, an explicit title and subtitle.Sensitivity module: plots are interactive with formatted tooltips, the range sliders no longer show tick marks, a note is shown when the prior is a mixture (the analysis uses a moment-matched working prior), and the "Analysis type" and outcome buttons clearly distinguish the selected option.
Dark mode: plotly plots are now recoloured natively instead of through a CSS colour-inversion filter, so plot colours and hover labels are correct and plots no longer flash light after an analysis is run.
prior_conflict() gains an exact argument (default FALSE, matching
prior behaviour exactly). exact = TRUE replaces the Normal
approximation to the prior and to the data likelihood -- used by
default for box_pvalue and the s_value derived from it -- with the
exact prior predictive distribution, for the prior family/data-type
combinations where one has a closed form: Beta-Binomial (a Beta
prior against type = "binary" data) and Gamma-Poisson/Negative
Binomial (a Gamma prior against type = "poisson" or
type = "survival" data -- both reduce to the same events/exposure
model, so one exact check covers both). The Normal-Normal case
(type = "continuous" against a Normal prior) was already exact and
needs no separate path. For prior family/data-type
combinations with no closed-form check implemented, exact = TRUE
falls back to the Normal approximation with a message rather than
erroring; $box_pvalue_method on the returned object reports which was
used ("exact" or "normal_approx"). surprise_index,
kl_prior_likelihood, and overlap are unaffected by exact, since
they are defined with respect to the Normal-approximated prior and
likelihood regardless.
Added map_prior(): derives a meta-analytic-predictive (MAP) prior from
historical trial summaries via a random-effects meta-analysis, with an
explicit prior on the between-trial heterogeneity parameter tau
(Schmidli et al., 2014). The meta-analysis engine is implemented
entirely in base R: the posterior of mu given tau has a closed form, so
the only numerical step is a one-dimensional integral over tau
(stats::integrate()/stats::optimize()/stats::uniroot(), all base
R) -- bayprior has no dependency, direct or optional, on any external
meta-analysis package for this. outcome_type presets select the
default tau prior from Roever et al. (2021)'s outcome-specific
recommendations, distinguishing a single-arm log-odds case (e.g.
historical control response rates -- the typical MAP use case) from a
two-arm log-odds ratio case, which get different default
heterogeneity-prior scales despite both being "log-odds" in casual
speech.
Added historical_effect_sizes(), a thin wrapper around
metafor::escalc() (Suggests, not Imports) that converts raw
per-trial summary statistics (event counts, arm means/SDs, ...) into
the y/se inputs map_prior() expects, across all six supported
outcome_types.
Added a Shiny module for map_prior(), "MAP Prior (Historical)", as
its own top-level sidebar item alongside "Prior Elicitation" and
"Expert Pooling" -- reflecting that MAP derivation is an alternative
way to construct a base informative prior, not a robustness adjustment
applied to one (Robust Mixture, Sceptical, and Power Prior all take an
existing base prior as input; MAP produces one). Its step-completion
indicator is tracked independently of Robust Priors' own.
prior_conflict() now also reports s_value, the surprisal
-log2(box_pvalue) in bits -- an exploratory,
continuous companion to the existing Box p-value / thresholded
conflict_severity classification, since prior-data conflict checks are
typically not powered for a binary accept/reject decision. Reported
alongside (not instead of) the existing diagnostics in the console
print() method, the Shiny Conflict Diagnostics tab, and the
prior_report() regulatory report.
Restyled the app around the package palette (navy and emerald). The
stylesheet custom.css shipped with the app but was never linked, so
it had no effect; it is now loaded, with dark-mode variants. Result
tiles, box headers, alerts, and notifications use colour for status
only, and text colours were checked for WCAG AA contrast.
The Welcome page workflow diagram is now live: steps link to their panels and show completed steps. A "Start here" panel (elicit, derive from historical trials, or load the TRIAL-001 example) becomes "Next steps" once a prior exists. The Report step is marked complete after a report is generated and reopens when the prior or any analysis changes.
Fitting a prior (Parametric, Roulette, or MAP) while a pooled consensus prior is active now asks whether to replace the consensus or keep it, instead of leaving downstream steps on the old consensus without notice.
Fixed a JavaScript error in the theme-toggle script, which ran before the page body existed and stopped the rest of the script from loading. The Auto / Dark / Light button label now shows correctly on load.
sensitivity_grid() and sensitivity_cri() now moment-match a mixture
prior's actual pooled mean and SD to a working prior, instead of
silently analyzing only the dominant component by weight. Under equal
or near-equal expert weights, this previously meant the sensitivity
grid could reflect a single expert's prior without any indication that
other experts' input had been dropped. A message now reports the
working prior used; a warning is issued if the mixture's family cannot
be moment-matched from mean/SD (Exponential, Weibull), in which case
the dominant-component fallback is used and clearly identified.
Fixed the pairwise Bhattacharyya agreement coefficient
(aggregate_experts()) silently reporting near-total disagreement for
any pair of experts using Lognormal, Exponential, or Weibull priors
(or Gamma, via a related integration-range issue), regardless of how
similar their actual priors were. This always triggered the "substantial
expert disagreement" warning for these families.
Fixed plot() on a bayprior_conflict object and plot_prior_likelihood()
silently clipping the likelihood curve when it falls substantially
outside the prior's own range. Both functions previously built their
plotting grid from the prior's range alone; since these plots exist
specifically to visualise prior-vs-data agreement or conflict, a
genuinely severe conflict (the case the plot is meant to surface) could
mean the likelihood curve was dropped from the visible range entirely.
The grid now spans both the prior's and the likelihood's range.
Fixed plot() on a bayprior_conflict object erroring for any prior
other than Beta (Normal, Gamma, Lognormal, Exponential, Weibull), and
the plotted x-axis range being incorrectly clamped to [0, 1] regardless
of the prior's actual support.
Fixed plot_prior_likelihood()'s likelihood curve for Poisson/count and
survival data types being centred at the raw event count rather than
the event rate, and referencing an SD field that is never collected for
these data types (only continuous data has one). This affected the
"Prior-Likelihood-Posterior overlay" panel in the Shiny app's Conflict
Diagnostics tab for any Poisson or survival analysis.
Fixed .conjugate_update() aborting for any prior/data-type pairing
with no exact conjugate formula (e.g. a Beta prior with continuous
data), which contradicted the compatibility warning shown elsewhere in
the package promising the analysis would proceed via a Normal
approximation. Now falls back to a Normal-approximation posterior
instead, consistent with that promise. This also fixes the Shiny app's
"Prior-Likelihood-Posterior overlay" panel erroring ("Could not update
any mixture component with the supplied data") for a pooled mixture
prior with any component/data-type pairing lacking an exact conjugate
update.
Removed a duplicate, dead definition of sensitivity_cri() that had
fallen out of sync with the version actually in use; the live version
had the same mixture-handling issue described above, now fixed.
Fixed a crash (argument is of length zero) in mixture-handling logic
when called on a logarithmically-pooled prior, whose fit_summary$sd
is NULL by design.
sensitivity_grid()'s Shiny UI parameter-range defaults now use the
same working-prior logic as the underlying function, so the interface's
suggested ranges no longer risk diverging from what is actually
analyzed.
Corrected the documented meaning of null_value for
sceptical_prior(..., family = "lognormal"): it must be supplied on
the log scale (e.g. 0 for a null hazard ratio of 1), not the natural
scale implied by the previous generic parameter documentation.
Fixed conflict_mahalanobis()'s documented return field names
(mahal_d2, p_value), which did not match the object's actual field
names (mahal_D2, pvalue).
Corrected the title of the FDA's 2026 draft guidance as cited throughout the package documentation, vignettes, Shiny app, and regulatory report template. The guidance is titled "Use of Bayesian Methodology in Clinical Trials of Drug and Biological Products."
Updated the EMA reference in the regulatory report, Shiny app, and vignettes to reflect the agency's current published position: a 2026 concept paper proposing the development of guidance on Bayesian methods (EMA/CHMP/1813/2026), with the full reflection paper expected in 2027-2028.
Corrected the FDA guidance section references in the
regulatory-reporting vignette's compliance-checklist table to match
the guidance document's structure (Sections V.A, V.C, V.D, V.F, and
VIII.B).
Clarified attribution of the sceptical prior and the enthusiastic/ sceptical sensitivity pairing to Spiegelhalter & Freedman (1994).
Removed an inaccurate cross-reference to ICH E9(R1) in the
sensitivity-analysis vignette; ICH E9(R1) addresses estimands and
intercurrent events rather than prior specification.
Aligned the package website overview (index.qmd) with the README's
description of related packages.
print.bayprior(), print.bayprior_conflict(),
print.bayprior_conflict_mv(), and print.bayprior_power_prior()
producing no output when called inside rmarkdown::render(), knitr
vignettes, or any non-interactive R subprocess (e.g. callr::r()).
Output now renders correctly in both interactive and non-interactive
sessions (#40).Wrapped software name in single quotes in DESCRIPTION: 'Shiny', per CRAN policy on package and software name formatting.
Added six methodology references to DESCRIPTION in CRAN-required format (authors, year, doi/ISBN): O'Hagan et al. (2006), Box (1980), Oakley and O'Hagan (2010), Schmidli et al. (2014), Ibrahim and Chen (2000), Spiegelhalter et al. (1994).
Added \value documentation tag to four exported print methods:
print.bayprior(), print.bayprior_conflict(),
print.bayprior_conflict_mv(), and print.bayprior_power_prior().
Each documents that the function returns the input object invisibly,
called for its side effect of printing a formatted summary.
Restored par() settings after use in the robust-priors vignette.
The par(oldpar) call was incorrectly placed before the for loop
and legend(). Moved to after all plotting operations, per CRAN policy.
Removed LICENSE file and | file LICENSE from DESCRIPTION. The GPL-3
licence does not require an additional file.
Updated inst/WORDLIST: added biom, doi, and ss -- fragments
extracted by the spell checker from DOI strings in the DESCRIPTION
references field.
.Rbuildignore pattern for cran-comments.md.
The pattern ^^cran-comments\\.md$$ (double caret, double dollar)
never matched the file, so it was included in every previous tarball.
Fixed to the correct regex ^cran-comments\.md$ and verified absent
from the v0.2.11 tarball.Switched Language from en-US to en-GB in DESCRIPTION to correctly
reflect the British English used throughout the package (sceptical, colour,
behaviour, normalised etc.). British spellings are now handled by the en-GB
dictionary and no longer need to be in inst/WORDLIST.
Replaced "Kullback-Leibler divergence" in DESCRIPTION with "information
divergence". Kullback and Leibler are proper nouns not in any standard
dictionary and cannot be resolved via inst/WORDLIST for CRAN's DESCRIPTION
spell check.
Updated inst/WORDLIST: added HR, Inf, Var, heatmaps, prior's, R's,
VignetteBuilder, Poisson, etc. Removed British spellings now covered by
en-GB dictionary.
inst/WORDLIST. These are proper nouns
(the Kullback-Leibler divergence is named after statisticians Solomon
Kullback and Richard Leibler) and are standard terminology in Bayesian
statistics. Flagged as possibly misspelled by CRAN's automated pre-check
in v0.2.8.Resolved the persistent "Package has a VignetteBuilder field but no
prebuilt vignette index" NOTE that appeared across v0.2.4--v0.2.7.
Root cause: ^build$ was incorrectly added to .Rbuildignore, which
excluded build/vignette.rds from the tarball. This file is generated
by R CMD build during vignette processing and is the exact file
R CMD check looks for (tools/R/QC.R). Removing ^build$ from
.Rbuildignore resolves the note permanently.
Revised Description field in DESCRIPTION to remove all regulatory body
references and abbreviations. The description now describes what the
software does. Regulatory context is retained in vignettes and README.
Resolve EMA in DESCRIPTION. The EMA acronym (European Medicines Agency)
was flagged as a possible misspelling in the DESCRIPTION file, causing a
CRAN resubmission WARNING.
Updated inst/WORDLIST.
Updated inst/WORDLIST to include all package-specific terms flagged by
the spelling checker, and package infrastructure terms (golem,
shinydashboard, knitr, pandoc). Resolved spelling.Rout vs
spelling.Rout.save mismatch in tests.
Changed Language field in DESCRIPTION from en-US to en-GB to reflect
the package's consistent use of British English spelling throughout
documentation and vignettes (sceptical, colour, behaviour, centred).
Added prebuilt vignette index (inst/doc/index.html) to resolve the
"no prebuilt vignette index" NOTE reported by CRAN's automated pre-check
on Windows and Debian.
Removed all Unicode characters from R source files that caused LaTeX PDF generation errors on CRAN's Windows and Debian build servers. Affected characters: U+2014 em dash (replaced with --), U+2212 Unicode minus (replaced with -), U+221E infinity (replaced with Inf), U+2019/U+2018 curly quotes (replaced with '), and others. All replacements made in comments and roxygen documentation only -- no functional code changed.
Added inst/WORDLIST declaring package-specific acronyms (EMA, FDA, CrI,
MAP, Mahalanobis, Bhattacharyya, SHELF, PFS, PK) that were flagged as
possibly misspelled in the DESCRIPTION file.
Rebuilt prebuilt vignette index via devtools::build_vignettes() to
resolve the "no prebuilt vignette index" NOTE.
robust_prior() -- added @details section explaining that the vague
component is always Normal, making cross-family mixtures (e.g. Beta +
Normal) structurally inevitable for non-Normal informative priors.
elicit_mixture() -- added @details section documenting the numerical
density approximation behaviour at the lower level where mixtures are first
constructed.
Robust Mixture density plot warning redirected from console to UI. The
"Components have different distribution families. Mixture densities computed
numerically." warning is now surfaced as an amber showNotification() in
the Shiny app.
Introduced shared$base_prior reactive to eliminate the self-invalidation
loop that wiped sensitivity/robust/power prior results immediately after
they were produced.
Fixed robust mixture compounding SD bug -- repeated clicks no longer compound the vague SD exponentially.
tests/testthat/test-robust.R (33 tests).tests/testthat/test-validation.R (10 tests).skip_on_ci() to all shinytest2 Chromote tests.pkgload::load_all() from app.R.renv::snapshot(type = "explicit") to deployment workflow.elicit_exponential() -- Exponential(rate) prior for hazard rates and
Poisson rate priors. Supports moments, rate, and quantile methods.
elicit_weibull() -- Weibull(shape, scale) prior for survival times.
Supports moments, params, and quantile methods.
"poisson" and "survival" data types in prior_conflict(),
sensitivity_grid(), and sensitivity_cri().
Density and x-range support for Exponential and Weibull in plot.bayprior().
Comprehensive validation layer: .check_prior_data_compat(),
.check_pooling_compat(), .check_sensitivity_compat(),
.validation_alert().
Sensitivity analysis fully independent of conflict diagnostics.
All Shiny modules reset outputs automatically on input change.
prior_report() blank figures in Word reports.prior_report() PDF "tikzfill.image.sty not found" error.mod_conflict_mahal.R stale duplicate definition of mod_conflict_ui.Fixed prior_report() failing on remote platforms due to Quarto spawning
a subprocess that could not find the bayprior package.
Fixed mod_sensitivity always using type = "continuous" regardless of
prior family.
Fixed non-ASCII characters in R/app_ui.R causing R CMD check WARNING.
Fixed prior_report() missing @param documentation for plot arguments.
Added robust, sceptical, and power prior arguments to prior_report().
Added bayprior hex logo to Shiny app header and browser favicon.
elicit_beta(), elicit_normal(), elicit_gamma(),
elicit_lognormal(), elicit_roulette(), elicit_mixture().aggregate_experts() with Bhattacharyya diagnostics.prior_conflict(), conflict_mahalanobis().sensitivity_grid(), sensitivity_cri().robust_prior(), sceptical_prior(),
calibrate_power_prior().prior_report() (HTML, PDF, Word).run_app().