Contributor-facing project documentation, release baselines, and changelog material.
Pages
Contributing — This guide covers the development setup, conventions, and workflow for contributing to meridian-tools.
Acceptance checklist — Use this page as the canonical local acceptance checklist for the current repository state. The acceptance gate is local and command-driven, and it uses the same script as CI.
Release baseline — This page records the 0.4.0 release-candidate baseline for the repository. Treat it as a validated project state, not as an automated release system. The baseline uses the canonical constrained verification script and records the observed warning profile, the direct runtime dependency bounds, and the accepted trade-offs that still shape the package.
Changelog — All notable changes to meridian-tools are documented in this file.
Meridian Compatibility Inventory — This project currently targets google-meridian[schema]==1.5.3. The local reference checkout used for compatibility review is:
Subsections of Project
Contributing
This guide covers the development setup, conventions, and workflow for
contributing to meridian-tools.
All public functions and classes use type annotations. The codebase uses
from __future__ import annotations for forward-reference support.
Import conventions
Standard library imports first, then third-party, then local.
Heavy dependencies (Meridian, TensorFlow, ArviZ) are imported lazily inside
functions, not at module level, in the config/CLI/validation layers.
Ruff rule I enforces import sorting.
Configuration models
All Pydantic models use ConfigDict(extra="forbid"). New config fields must
be added with appropriate types, defaults, and validators.
Testing
Running tests
# Full suitepython scripts/verify_release.py
# Specific filepytest tests/test_runner.py -v
# Specific testpytest tests/test_runner.py::test_run_pipeline_writes_manifest -v
Test conventions
Tests use pytest with tmp_path for temporary directories.
monkeypatch is used extensively to mock Meridian internals and isolate
unit tests from real MCMC sampling.
Module-scoped fixtures (scope="module") are used for expensive model
construction in test_log_likelihood.py and test_model_selection.py.
Shared test infrastructure is defined inline in individual test modules.
There is no top-level conftest.py.
Live Meridian verification
One opt-in command exercises the bounded real Meridian seam:
This is not part of the default suite. It proves one reduced real pipeline run
over bundled demo data, one stored-run refresh after the original YAML is
removed, and the lower-level live log-likelihood seam. Run it after Meridian
version upgrades and before release-candidate handoff when you want extra
confidence beyond the fast suite.
Writing new tests
Place tests in the appropriate tests/test_<module>.py file.
Use monkeypatch to avoid real MCMC sampling in unit tests.
Test both success paths and error conditions.
Verify artefact file contents, not just their existence.
The version is defined in src/meridian_tools/version.py:
__version__="0.4.0"
Version bumps are manual edits. Update this file when preparing a release.
Documentation
Documentation lives in docs/. When adding new features:
Update relevant guide or reference pages.
Add API documentation for new public functions or classes.
Update the YAML schema reference if config fields changed.
Update the output schema if new artefacts are produced.
Common pitfalls
Do not import Meridian at module level in config, CLI, or validation
modules. This breaks CLI responsiveness.
Do not add extra="allow" to Pydantic models. The extra="forbid"
policy prevents silent misconfiguration.
Do not modify source run directories in lifecycle operations. Always
create new sibling directories.
Do not weaken or delete existing tests without explicit direction.
Acceptance checklist
Use this page as the canonical local acceptance checklist for the current
repository state. The acceptance gate is local and command-driven, and it uses
the same script as CI.
Acceptance gate
Run the following commands from the repository root:
The canonical acceptance-gate result for the full test step in the current
constrained environment is:
485 passed, 2 skipped
That result is the pass or fail line for the default local acceptance gate.
The recorded warning profile belongs to the release baseline, not to the
acceptance-gate definition itself.
What each command proves
python -m pip check proves that the active constrained environment has no
broken package requirements.
python -m compileall src tests scripts runme.py proves that the checked-in Python files parse
cleanly. If this step fails, you are dealing with a syntax or import-time
parse issue and you should stop there.
python -m meridian_tools.cli --help and python runme.py --help prove that
the installed CLI and source-tree launcher surfaces still import cleanly.
ruff check src tests scripts runme.py proves that the repository still satisfies the pinned
lint rules. If this step fails, fix the reported lint violations before moving
on.
ruff format --check src tests scripts runme.py proves that the checked-in files still match
the agreed formatting contract. If this step fails, run the formatter and then
rerun the verification sequence.
mypy src proves that the configured static typing baseline still runs
cleanly. If this step fails, either fix the reported type issue or update the
documented ratchet intentionally.
python docs-site/build_content.py, git diff --exit-code -- docs-site/content,
and hugo --source docs-site prove that canonical Markdown, generated Hugo
content, and the static site build stay aligned.
pytest --cov=src/meridian_tools --cov-report=term-missing proves the behavioural contract of the repository. This is
the broadest local validation step. If it fails, use the failing test names to
identify which package contract regressed.
How to interpret failure
If the compile step fails, fix syntax or parse problems first. The later steps
will not give you useful signal until that is resolved.
If lint, format, or type checks fail, treat that as a source-tree quality
issue, not as an optional clean-up item. Bring the tree back to the pinned
Ruff and mypy state before trusting the rest of the loop.
If CLI help fails, assume the published command surface is broken even if the
Python modules still import manually.
If the docs drift check fails, update the canonical files under docs/ first,
then regenerate docs-site/content.
If the pytest coverage step fails, the acceptance gate is not met. A partial pass is
not enough. Fix the failing behavioural contract and rerun the full command
sequence.
Optional extra confidence
The repository also carries one opt-in live Meridian verification command for
extra technical confidence:
This command is not part of the default blocking acceptance gate. It exists to
provide one bounded live Meridian route that proves:
real pipeline execution over bundled demo data
manifest-backed stored-run refresh after the original YAML is removed
the lower-level live log-likelihood reconstruction seam
On the reference development environment, the recorded run finished in 135.42
seconds (0:02:15), with command elapsed time of 2:24.03; keep a budget of
roughly six minutes or less for this extra-confidence command.
Release baseline
This page records the 0.4.0 release-candidate baseline for the repository.
Treat it as a validated project state, not as an automated release system. The
baseline uses the canonical constrained verification script and records the
observed warning profile, the direct runtime dependency bounds, and the
accepted trade-offs that still shape the package.
Release-ready definition in this repository
The repository is release-ready only when the documented local acceptance
command set passes, the coverage test step returns the recorded pass/skip
count below, the same validated run is recorded with the observed warning
profile, the warning categories match the accepted ones below, and the accepted
trade-offs remain explicit rather than hidden.
That command remains opt-in local confidence, not the default developer loop or
silent CI policy. On the reference development environment, the recorded run
finished in 135.42 seconds (0:02:15), with command elapsed time of 2:24.03;
keep a budget of roughly six minutes or less for ordinary local execution.
Certified environment
Python 3.12.11
meridian-tools==0.4.0
google-meridian==1.5.3
arviz==0.19.0
matplotlib==3.9.4
protobuf==6.33.6
ruff==0.14.0
mypy==1.18.2
pytest==8.4.2
Hugo 0.164.0
Runtime dependency boundary
The current runtime boundary recorded from pyproject.toml is:
requires-python >=3.11
google-meridian==1.5.3
arviz>=0.18.0,<0.20.0
constrained release gate uses arviz==0.19.0 and matplotlib==3.9.4
protobuf>=5.28.0,<7
constrained release gate uses protobuf==6.33.6
pandas>=2.2.0,<3
pydantic>=2.8.0,<3
PyYAML>=6.0.0,<7
These are the direct runtime dependency bounds for the milestone baseline. This
page does not imply broader environment reproducibility than the constrained
gate currently implements.
Accepted warning profile
The recorded warning profile is accepted in the current milestone baseline.
The warnings fall into these pinned categories:
Meridian model / prior warnings
ArviZ model-selection warnings
Matplotlib/Pyparsing deprecation warnings from the constrained ArviZ
compatibility line
Meridian schema/protobuf deprecation warnings caused by Meridian 1.5.3
serialising boolean TensorFlow Probability parameters through an int proto
path; protobuf 7 rejects that path, so this release candidate constrains
protobuf below 7
Hugo Relearn theme deprecation warnings during static-site build
This baseline does not pretend the repository is warning-free. It records the
current observed warning profile honestly and treats those warning categories as
accepted for the present milestone.
Accepted trade-offs
The current release baseline also depends on several explicit trade-offs.
The package takes a no-fork Meridian approach. We keep Meridian as the
modelling engine and add workflow and compatibility tooling around it rather
than modifying Meridian source.
Bayesian model selection remains intentionally limited to fitted Meridian
models where holdout_id is None. Validation-fit and authored-holdout runs are
not treated as compatible LOO or WAIC candidates.
Lifecycle tooling remains Python-first. The repository does not currently ship
a broader lifecycle CLI.
Version bumping remains a manual edit rather than a fully automated release
pipeline.
Boundary of this record
This page records one validated milestone state. It does not introduce CI as
the source of truth. It does not define publish automation. It does not promise
zero warnings. It does not claim a broader release process than the repository
actually supports today.
Changelog
All notable changes to meridian-tools are documented in this file.
YAML media priors — YAML-driven media prior configuration for roi_m,
mroi_m, and alpha_m, including scalar priors, per-channel overrides, and
support for Normal, LogNormal, TruncatedNormal, and Beta
distributions.
Prior distribution export — prior_distributions.json is written in the
model-fit stage so authored and resolved Meridian prior distributions are
captured with run artefacts.
Config templates — Commented starter configs under templates/ cover
minimal, standard, media-prior, and blocked-tail validation workflows.
Geo panel demo artefacts — Stored geo_panel demo run outputs now live
under runs/demos/, so reference artefacts cover both bundled pipeline
shapes.
Meridian compatibility inventory — Project documentation now records the
Meridian 1.5.3 files and private sampler seams that must be reviewed before
changing the dependency pin.
Validation-spec v2 bindings — Stored validation specs now bind
coordinate and data-shape metadata so refresh and rolling-origin execution
can fail closed when input data no longer matches the stored contract.
Ephemeral input provenance — Manifest v4 runs record provenance for the
exact temporary snapshot loaded by Meridian.
Canonical verification gate — scripts/verify_release.py now runs the
constrained release checks for dependency consistency, compile/import
health, CLI help, Ruff, mypy, Hugo docs, and the coverage suite.
Changed
Strict run names — Pipeline run names must now match
^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$; path separators, whitespace, Unicode,
and relative path segments are rejected before run directories are created.
CSV loader YAML validation — data.coord_to_columns and channel mapping
fields now fail earlier with wrapper-owned errors when shapes, keys, or
channel ordering are inconsistent with Meridian loader contracts.
ModelSpec array validation — Known boolean array kwargs forwarded through
model_spec.kwargs now reject scalars, ragged lists, strings, and numeric
stand-ins before Meridian model construction; their ranks and loaded-data
shapes are also checked before model construction.
Model-selection resilience — Optional LOO/WAIC exports now capture
ArviZ warnings and degrade to explicit status artifacts for unexpected
ArviZ or artifact-write failures instead of failing the whole run.
Bounded rolling-origin execution — Each split fits only through its test
boundary and records the exact validation window used for execution.
Manifest v4 completion integrity — Completed runs validate required
manifest artefacts as existing, contained regular files before the final
manifest is written.
Release documentation — Architecture, schema, release-baseline, and
generated Hugo documentation now describe manifest v4, validation-spec v2,
bounded reproducibility, and the canonical constrained gate.
Fixed
Launcher empty-result handling — The source-checkout launcher now raises
a clear runtime error if the pipeline unexpectedly returns no run result.
Run directory collisions — Same-second runs with the same logical name
now use deterministic suffixes such as _001 instead of failing on an
existing directory.
Private destination JSON writes — Newly created destination JSON files
now use private file modes.
Temporary snapshot cleanup — Temporary Meridian input snapshots are
removed after handoff while hashed provenance for the loaded bytes is kept.
Finite numeric configuration — Non-finite numeric, analysis, and nested
Meridian configuration values are rejected before they reach Meridian.
Repo-owned Hugo configuration — The repository-owned Hugo language
setting no longer emits a deprecation warning on the supported Hugo line.
Protobuf compatibility bound — The supported dependency boundary now
constrains protobuf<7 because Meridian 1.5.3 serialises boolean TensorFlow
Probability parameters through an int proto path that protobuf 7 rejects.
[0.3.0] — 2026-04-24
Changed
CLI single source of truth — runme.py now delegates directly to
meridian_tools.cli, removing duplicate root-level argument parsing.
Typed runner state — Pipeline orchestration now uses PipelineContext
for shared stage state.
Shared posterior sampling — Runner posterior sampling keyword mapping is
centralized in one helper.
Lifecycle comparison schema — Run comparison rows are generated from
declarative comparison field descriptors.
Meridian compatibility pin — The package pins
google-meridian[schema]==1.5.3, and log-likelihood reconstruction refuses
unvalidated Meridian versions.
Static analysis tooling — Development extras now include mypy, and
Ruff enables additional complexity, simplification, and Ruff-specific rule
families.
Fixed
Optimized Python safety — Validation helpers now use explicit exceptions
instead of assert for runtime invariants.
Shared confidence validation — Response curve and optimisation configs
share one confidence_level validator.
Export coercion documentation — NetCDF attribute coercion now documents
its input-to-output type mapping.
[0.2.0] — 2026-04-07
Added
Docs site build — Hugo-based website documentation under docs-site/,
generated from the repository Markdown set by
docs-site/build_content.py.
Manifest v3 provenance — Explicit input_data_provenance capture for
stored runs and lifecycle refresh or compare workflows.
Typed failure boundaries — ConfigPreflightError,
ValidationExecutionContractError, and PipelineRunFailure distinguish
wrapper-owned preflight, validation contract misuse, and post-directory
runtime failures.
Bounded live verification — An opt-in Meridian real-fit smoke route
gated behind MERIDIAN_TOOLS_ENABLE_REAL_FIT=1.
Module-path CLI contract — Explicit support and regression coverage for
python -m meridian_tools.cli ....
Changed
Shared launch flow — meridian-tools and the repo-root runme.py
launcher now share one launch flow for config loading, preflight checks,
progress reporting, and terminal success or failure output.
Packaged demo assets — Bundled demo configs and datasets are resolved
from packaged _demo_data, so demo runs work from installed wheels as well
as source checkouts.
Default demo fit mode — Bundled demos now default to full-sample fits
(validation.strategy: none), so loo_summary.json and waic_summary.json
are generated by default and 10_validation is recorded as skipped.
Refresh contract — Stored-run refresh now reloads from the saved
resolved config while preserving the original source config copy in run
metadata.
Lifecycle compare semantics — Compare now distinguishes legacy runs
without dataset provenance from real dataset changes.
Documentation layout — Public documentation is reorganised under docs/
into getting-started, guides, reference, concepts, and project sections.
Fixed
Structured public entrypoint failures — Missing or invalid config paths
in public entrypoints now produce structured failure output instead of raw
Python tracebacks unless --traceback is used.
Relative-path refresh — Refreshing a stored run with relative
data.path input no longer depends on the original source config location
remaining present on disk.
Partial-run failure reporting — Failed runs that already created an
output directory now report the concrete run directory, manifest path, and
failing stage through the CLI and runme.py.
Docs-site theme resolution — Hugo builds resolve the Relearn theme
through a pinned module dependency instead of requiring a local theme
checkout.
[0.1.0] — 2026-04-02
Added
Typed YAML configuration — Pydantic-validated config with extra="forbid"
strictness for all sections: project, data, model_spec, fit,
validation, exports, response_curves, optimisation.
Staged pipeline runner — Sequential execution through 00_run_metadata,
10_validation, 20_model_fit, 30_model_assessment, 40_decomposition,
60_response_curves, 70_optimisation with manifest persistence after each
stage.
Validation orchestration — blocked_tail and rolling_origin time-series
validation strategies with auto-generated holdout masks. Authored holdout
passthrough through model_spec.kwargs.holdout_id.
Diagnostics bundling — diagnostics_bundle.json manifest with optional
predictive_accuracy.csv and review_summary.json exports.
Bayesian model selection — Compatibility-aware LOO and WAIC computation
through ArviZ, with automatic log-likelihood reconstruction for fitted Meridian
models. Graceful degradation for incompatible runs through structured
ModelSelectionError with reason codes.
Response curves export — Configurable spend multiplier grid with NetCDF
and CSV outputs.
Optimisation export — Fixed-budget and relative-budget optimisation with
full artefact set including allocation charts.
Plot exports — PNG plot artefacts through Altair/vl-convert for model fit,
diagnostics, decomposition, response curves, and optimisation stages.
Lifecycle management — load_run_record, list_run_records,
build_refresh_run_config, compare_run_records for post-run analysis and
reproducible refresh workflows.
CLI — meridian-tools run and meridian-tools demo subcommands with
lightweight imports for fast startup.
Bundled demos — timeseries and geo_panel reference workflows with
packaged data and configs.
Manifest versioning — Support for manifest versions 0, 1, and 2 with
backward-compatible deserialisation.
Comprehensive test suite — 218 tests across 15 test files covering
configuration, validation, pipeline execution, exports, diagnostics, model
selection, lifecycle, and demos.
Meridian Compatibility Inventory
This project currently targets google-meridian[schema]==1.5.3. The local
reference checkout used for compatibility review is:
/home/user/Documents/GITHUB/tandpds/meridian
The 0.4.0 release-candidate environment also constrains
protobuf>=5.28.0,<7. Meridian 1.5.3 serialises boolean TensorFlow
Probability distribution parameters through an int proto path. Protobuf 7
rejects that path, while the constrained protobuf==6.33.6 line preserves the
validated Meridian schema save/load smoke route with deprecation warnings.
Reviewed Reference Files
meridian/version.py
meridian/data/load.py
meridian/model/spec.py
meridian/model/context.py
meridian/model/model.py
meridian/model/posterior_sampler.py
Required Symbols And Contracts
meridian.version.__version__ is 1.5.3.
protobuf remains below 7 for Meridian schema serialisation.
meridian.data.load.CoordToColumns defines the CSV coordinate mapping surface.
meridian.data.load.CsvDataLoader is the CSV input loader used by meridian-tools.
meridian.model.spec.ModelSpec accepts wrapper-authored kwargs, including
holdout_id and calibration/scaling arrays.
ModelContext.holdout_id validates national holdout masks as (n_times,)
and geo holdout masks as (n_geos, n_times).
Meridian.posterior_sampler_callable returns a posterior sampler with the
private reconstruction seams required by the log-likelihood adapter.