Analysis Manifests and Reproducible Bayesian Workflows

A manifest is an analysis contract about the analysis contract

A fitted model is not enough to reconstruct an analysis decision process. gp3bayes 0.2.0 therefore provides an analysis manifest that records the approved model contract, preparation/transformation record, specification, prespecified estimands, sensitivity plan, seed, backend metadata, software versions, and a fingerprint of the analysis data.

The manifest stores a fingerprint rather than duplicating the analysis data. It is provenance metadata, not a hidden data archive.

Create a manifest before fitting

simulation <- simulate_hierarchical_binary_data(
  n_participants = 10,
  trials_per_participant = 8,
  n_items = 5,
  random_slope_sd = 0,
  seed = 42
)

contract <- create_model_contract(
  "binary", "selected", "participant_id",
  item_col = "item_id",
  trial_col = "trial_id",
  condition_col = "condition"
)

prepared <- prepare_hierarchical_binary_data(
  simulation$data,
  contract,
  condition_levels = c("control", "treatment")
)

specification <- specify_binary_model(prepared, baseline = 0.35)

manifest <- create_analysis_manifest(
  specification = specification,
  estimands = "standardized_probability_contrast",
  seed = 2026,
  label = "Synthetic binary release case"
)

manifest
#> <gp3bayes_analysis_manifest>
#>   Version: 0.2
#>   Label: Synthetic binary release case
#>   Family: binary
#>   Data: 80 x 8
#>   Data hash: 09ab941d91559d015dc9fe304ebfb2e7
#>   Frozen: FALSE
analysis_manifest_table(manifest)
#>              component                            value
#> 1               family                           binary
#> 2         model_family              hierarchical_binary
#> 3            data_hash 09ab941d91559d015dc9fe304ebfb2e7
#> 4        contract_hash a004cd56a9d35cff138e36f46a836579
#> 5   specification_hash 309b774249f3f72e44c7e76d8a98f318
#> 6  transformation_hash bb87585a96dfafaf1dc60c74014e0038
#> 7                 seed                             2026
#> 8              backend                             <NA>
#> 9               frozen                            FALSE
#> 10       manifest_hash                             <NA>
validate_analysis_manifest(manifest)
#> <gp3bayes_manifest_validation>
#>   Status: pass
#>             check status                           detail
#>    manifest_class   pass       gp3bayes_analysis_manifest
#>   required_fields   pass                         complete
#>  data_fingerprint   pass 09ab941d91559d015dc9fe304ebfb2e7
#>   approved_family   pass                           binary

Freeze only when the analysis-defining fields are ready

Freezing computes a manifest hash. With file = NULL, no file is written.

frozen <- freeze_analysis_manifest(manifest)
frozen
#> <gp3bayes_analysis_manifest>
#>   Version: 0.2
#>   Label: Synthetic binary release case
#>   Family: binary
#>   Data: 80 x 8
#>   Data hash: 09ab941d91559d015dc9fe304ebfb2e7
#>   Frozen: TRUE
#>   Manifest hash: 20fba3737ca2d81bb535d8f8ccb24b7f

Writing is always explicit. Temporary files are used here so the vignette does not write into the package or working directory.

manifest_file <- tempfile(fileext = ".rds")
report_file <- tempfile(fileext = ".md")

freeze_analysis_manifest(manifest, file = manifest_file)
#> <gp3bayes_analysis_manifest>
#>   Version: 0.2
#>   Label: Synthetic binary release case
#>   Family: binary
#>   Data: 80 x 8
#>   Data hash: 09ab941d91559d015dc9fe304ebfb2e7
#>   Frozen: TRUE
#>   Manifest hash: 20fba3737ca2d81bb535d8f8ccb24b7f
restored <- read_analysis_manifest(manifest_file)
write_reproducibility_report(restored, report_file)

file.exists(manifest_file)
#> [1] TRUE
file.exists(report_file)
#> [1] TRUE

unlink(c(manifest_file, report_file))

Compare analysis provenance

A difference is reported, not judged automatically.

alternative <- create_analysis_manifest(
  specification = specification,
  estimands = "standardized_probability_contrast",
  seed = 2027,
  label = "Alternative seed"
)

comparison <- compare_analysis_manifests(manifest, alternative)
comparison
#> <gp3bayes_manifest_comparison>
#>   Identical: FALSE
#>   Changed: seed
plot(comparison)

This comparison is particularly useful during revisions, refits, or a package upgrade: it makes changes to the data fingerprint, transformations, priors, estimands, seed, backend settings, or software environment visible without pretending that every difference is scientifically consequential.