Contributing
This page details the guidelines to follow when contributing to ConvolvedDistributions.jl.
Getting started
Before contributing, please:
Read the Getting started with Julia guide if you are new to Julia development
Install Task for the development workflows below:
macOS:
brew install go-task/tap/go-taskLinux: Download from releases or use your package manager
Windows:
winget install Task.Taskor download from releases
Check out the developer documentation for advanced workflows
Review the project structure and development commands below
Project structure
ConvolvedDistributions.jl uses several environments for different purposes.
ConvolvedDistributions.jl/
├── Project.toml # Main package environment
├── src/ # Package source
│ ├── ConvolvedDistributions.jl # Module file: exports and centralised imports
│ ├── docstrings.jl # DocStringExtensions @template registration
│ ├── interface.jl # AbstractCombinedDistribution family supertype
│ ├── Convolved.jl # convolve_distributions and the Convolved type
│ ├── Difference.jl # difference and the Difference type
│ ├── convolve_with_vector.jl # timeseries form of convolve_distributions
│ ├── solvers.jl # AnalyticalSolver / NumericSolver method types
│ ├── integration.jl # shared Gauss-Legendre quadrature layer
│ ├── gamma_ad.jl # AD-safe gamma CDF helpers
│ ├── TestUtils.jl # interface-contract verifiers for the family
│ └── public.jl # public (non-exported) bindings
├── ext/ # Package extensions (AD rules, Integrals,
│ # Optimization quantile, SurvivalDistributions)
├── test/
│ ├── Project.toml # Test environment
│ ├── runtests.jl # Main test entry (TestItemRunner)
│ ├── distributions/ # Unit tests (Convolved, Difference, quantile,
│ │ # timeseries convolution)
│ ├── integration/ # Quadrature-layer tests
│ ├── package/ # Quality gates plus the family interface test
│ ├── ad/ # AD gradient harness (own environment)
│ ├── jet/ # JET static analysis (isolated environment)
│ ├── formatter/ # JuliaFormatter check (isolated environment)
│ └── ADFixtures/ # AD gradient scenario registry
├── docs/
│ ├── Project.toml # Documentation environment
│ ├── make.jl # Documentation build script
│ ├── pages.jl # Documentation navigation tree
│ └── src/ # Documentation source files
└── benchmark/
├── Project.toml # Benchmark environment
└── benchmarks.jl # Benchmark suite definitionFiles carrying a MANAGED by EpiAwarePackageTools.scaffold header are owned by the shared kit and rewritten on every sync. See Infrastructure and template sync for which files are managed and which are yours to edit.
Development commands
This project includes a Taskfile for the development workflows.
Quick start with tasks
# Discover all available tasks
task --list
# Common development workflow
task setup # One-time environment setup (all sub-environments)
task dev # Format + pre-commit + fast tests + fast docs
task precommit # Pre-commit validation
# Individual workflows
task test-fast # Quick testing (skips quality checks)
task docs # Full documentation build
task benchmark # Run benchmarksDetailed commands
For advanced usage, or when tasks don't cover a specific need, use the underlying Julia commands:
# Full test suite (recommended for CI and final checks)
julia --project=. -e 'using Pkg; Pkg.test()'
# Run tests directly (faster during development)
julia --project=test test/runtests.jl
# Skip quality tests for faster development iteration
julia --project=test test/runtests.jl skip_quality
# Run only the quality tests
julia --project=test test/runtests.jl quality_only
# Build complete documentation (includes Literate tutorial processing)
julia --project=docs docs/make.jl
# Execute the benchmark suite
task benchmarkTesting strategy
Test organisation
Unit tests: In
test/distributions/(Convolved.jl,Difference.jl,quantile.jl,convolve_with_vector.jl) plus the quadrature-layer tests intest/integration/Quality tests: Located in
test/package/, tagged:quality, alongside the family interface test (interface.jl)AD gradient tests: Located in
test/ad/, tagged:ad, with their own environment and dedicated per-backend CI
Tests are @testitems discovered with TestItemRunner. The main entry (test/runtests.jl) accepts skip_quality, quality_only, and readme_only arguments to scope discovery, and excludes :ad-tagged items (they run from test/ad/runtests.jl).
Quality gates
The quality gates in test/package/ guard the package's health:
Aqua.jl: Common package issues (stale deps, ambiguities, piracy)
ExplicitImports.jl: No implicit or stale imports, and import centralisation
JET.jl: Static analysis for type stability (run from the isolated
test/jetenvironment)JuliaFormatter: Formatting check (run from the isolated
test/formatterenvironment)Docstring format: Every docstring matches the
src/docstrings.jltemplateDoctest and README section checks, plus an extension-ambiguity check
Run them all with task test-quality, or a single isolated gate directly:
task test-jet # JET static analysis
task test-formatting # JuliaFormatter checkAD gradient harness
The convolution and difference log densities must differentiate cleanly across every backend the ecosystem uses. The harness in test/ad/ sweeps the scenarios registered in test/ADFixtures/ across six backends: ForwardDiff, ReverseDiff, Enzyme (reverse and forward), and Mooncake (reverse and forward), each an @testitem tagged for per-backend CI selection. The scenarios cover both the analytic and numeric (quadrature) paths of Convolved and Difference, plus the timeseries convolution.
task test-ad # all backends
task test-ad-backend TAG=enzyme_reverse # a single backendEach scenario carries a ForwardDiff reference gradient the other backends are checked against. When you add functionality touching the density or quadrature paths, add a matching scenario to test/ADFixtures/src/ADFixtures.jl so the sweep covers it.
Documentation
Literate.jl tutorials
The tutorials are Literate.jl scripts located in docs/src/getting-started/tutorials/. These are converted to markdown during the documentation build.
Tutorials are plain Julia .jl files using md"""...""" blocks for markdown. You can run them directly in the REPL or as scripts.
- Adding a new tutorial:
Create a
.jlfile indocs/src/getting-started/tutorials/Register it in
docs/docs_config.jland add the generated.mdfile todocs/pages.jl
- Tutorial format:
md"""
# Tutorial title
Introduction text.
"""
using ConvolvedDistributions, Distributions
md"""
## Section
"""
convolve_distributions(Gamma(2.0, 1.0), LogNormal(0.5, 0.4))Documentation structure
docs/src/getting-started/: User-facing documentationdocs/src/lib/: API documentation (auto-generated)docs/src/developer/: Developer and contributor documentation
Style guide
This project follows the SciML style guide.
Key points:
Use descriptive variable names
Follow Julia naming conventions (snake_case for variables, CamelCase for types)
Write docstrings for exported functions
Keep lines under 80 characters where possible
Use consistent indentation (4 spaces)
Documentation standards
All docstrings use the DocStringExtensions.jl @template conventions registered in src/docstrings.jl. That file is included near the top of the module, before any docstrings are defined, so the templates apply everywhere. The DocStringExtensions import itself lives in the module file (src/ConvolvedDistributions.jl) rather than in docstrings.jl, because the kit's import-centralisation gate requires every import to sit in the module file.
Functions: Use $(TYPEDSIGNATURES) for automatic signature generation:
@doc "
$(TYPEDSIGNATURES)
Brief description of the function.
# Arguments
- `param1`: Description (no type annotations needed)
- `param2`: Description
# Keyword Arguments
- `kwarg1`: Description
"
function my_function(param1, param2; kwarg1 = default)
# implementation
endStructs: Use $(TYPEDEF) with inline field documentation, which $(TYPEDFIELDS) renders:
@doc "
$(TYPEDEF)
Description of the struct.
"
struct MyStruct
"Description of field1"
field1::Type1
"Description of field2"
field2::Type2
endKey rules:
Never use
@doc raw"- it bypasses the template systemDon't repeat type information in argument descriptions, since
$(TYPEDSIGNATURES)shows themUse
@doc "(not@doc """) to allow macro expansion, unless the docstring carries LaTeX mathDocument argument purpose, not types
Benchmarks
The suite in benchmark/benchmarks.jl reads the cost of the convolution and difference operations on both the analytic and numeric quadrature paths.
task benchmark # benchmark the current state
task benchmark-compare # compare main vs current
task benchmark -- --filter=Convolved # filter to specific benchmarksBenchmark results recorded on main are rendered on the Benchmarks documentation page.
Code quality
Pre-commit checklist
Before submitting a pull request:
- Run pre-commit checks (recommended):
task precommit- Or run individual checks:
task test # Full test suite
task docs-fast # Build documentationAdding new features
Write tests first: Add a test file under
test/distributions/(ortest/integration/for quadrature work)Implement the feature: Add the type and constructor in
src/, following Adding a new combinationAdd an AD scenario: Register a gradient scenario in
test/ADFixtures/Document the feature: Add docstrings and update documentation if needed
Test thoroughly: Run the full test suite
Getting help
Questions: Open a GitHub discussion
Bugs: File a GitHub issue with a minimal reproducible example
Feature requests: Open a GitHub issue with rationale and use case
General Julia help: See Julia Discourse or Julia Slack
Thank you for contributing to ConvolvedDistributions.jl!