Provenance Implementation Plan#
This note defines a concrete provenance design for icclim outputs.
The goal is not to add more runtime logging. The goal is to write a
stable, machine-readable record of what was computed, from which inputs,
with which scientific options, and under which software context.
Why this is needed#
For climate-index production runs, users often need to answer questions after the run has finished:
which command or API call produced this output;
which files and variables were used;
which thresholds, reference periods, calendars and bootstrap options were applied;
which software stack and code revision produced the result;
whether important scientific warnings were emitted during the run.
Today, part of that information is present in NetCDF metadata such as
history and source, but not in a form that is complete enough for
systematic reconstruction of a run.
Design goals#
The provenance implementation should:
stay aligned with the scientific workflow visible in
icclimcode;record both user-facing parameters and important resolved parameters;
produce one stable JSON sidecar per written output;
keep a short summary in NetCDF global attributes;
degrade gracefully when some information is unavailable;
avoid collecting sensitive or noisy environment state by default.
FAIR4RS Alignment#
This provenance work is part of a broader FAIR4RS-oriented maintenance
direction in icclim.
The practical intent is:
make software behavior easier to inspect and reuse;
make generated outputs easier to interpret later;
keep scientific workflow decisions visible in code and in exported artifacts;
support reproducibility without requiring hidden terminal history or local memory of how a run was prepared.
In that sense, provenance is not an isolated utility feature. It is one
of the mechanisms used to make icclim outputs more reusable and
auditable as research software artifacts.
What to record#
Each written output should have a provenance bundle with these sections.
run_contextGeneral execution context.
UTC timestamp
hostname
current working directory
process id
Python executable
API entrypoint used, for example
icclim.indexoricclim.indices
softwareSoftware stack used for the run.
icclimversionPython version
versions of
xarray,numpy,pandas,dask,netCDF4,h5netcdf,cftime,zarr,xclimoptional numba version when present
gitRepository state when available.
repository root
branch
commit SHA
dirty state
short status summary
inputsInput datasets and variable-level context.
input paths or URIs
variable names selected from each input
file size and modification time when the input is local
optional checksum for small enough local files
outputsOutput artifact description.
NetCDF output path
output creation timestamp
optional checksum after write
provenance sidecar path
user_parametersParameters explicitly supplied by the caller.
index name or generic indicator
threshold expression
output frequency or seasonal selector
time range
base period or reference period
rolling window width
minimum spell length
output unit
bootstrap requested or not
save-threshold flag
sampling method
run-index mode
partial-season handling
resolved_parametersParameters and decisions resolved internally by
icclim.resolved indicator name
parsed threshold kind
percentile interpolation
day-of-year window width
detected source frequency
resolved reference period
calendar handling choices
whether a reference variable was built
bootstrap routing family
bootstrap execution route
executionRuntime context that can affect performance or reproducibility.
CPU count
dask scheduler kind when present
chunking description for main inputs when available
SLURM job identifiers when present
active conda environment or virtual environment when present
warningsStructured warnings collected during the run.
scientific warnings
fallback warnings
calendar-conversion warnings
chunking or performance warnings
warnings should remain concise and typed. It should not become a raw
dump of every Python warning emitted by dependencies.
icclim-specific mandatory fields#
The generic provenance idea must be specialized for climate-index runs. These fields should be treated as mandatory whenever relevant.
threshold semantics:
threshold string passed by the user;
resolved threshold class, for example bounded threshold, percentile threshold, fixed threshold;
percentile reference period;
percentile interpolation method;
day-of-year window width.
calendar semantics:
source calendar;
whether
ignore_feb29thoronly_leap_yearswas applied;whether any calendar coercion or alignment occurred.
bootstrap semantics:
whether bootstrap was requested;
whether bootstrap was actually active;
bootstrap family, for example count, value aggregate, spell;
route kind, for example reference bootstrap, exact tiled bootstrap, compiled exact bootstrap;
fallback reason when optimized routing was not used.
sampling semantics:
output frequency;
seasonal mode when relevant;
time subset supplied by the user;
resolved source frequency.
Without these fields, a later reviewer cannot reliably reconstruct the scientific meaning of the output.
Output artifacts#
For a written output
result.nc
the provenance implementation should write
result.prov.json
next to it.
NetCDF global attributes should also carry a compact summary:
historysourceicclim_versioncommandwhen availablegit_commitwhen availableprovenance_file
The JSON sidecar is the full artifact. NetCDF attributes only point to it and keep the most useful summary fields close to the data.
Current implementation status#
The first implementation phase is now in place.
Current behavior:
icclim.index(..., out_file=...)writes a.prov.jsonsidecar;NetCDF global attributes include compact provenance pointers:
icclim_versionprovenance_filecommandgit_commitwhen available
the sidecar currently records:
run context
software versions
git context when available
input variable summaries
output paths
resolved runtime parameters
execution context such as chunk shapes and HPC job identifiers when present
This is intentionally a small first phase. It already makes output files more reusable and inspectable, but it does not yet capture every scientific decision listed below.
Why the main output path is the right integration point#
The current write path in src.icclim.main already has a clean
separation:
_build_config_from_requestresolves the scientific request into anIndexConfig._compute_climate_indexcomputes the result and assembles standard metadata._write_output_filewrites the NetCDF output.
That makes _run_index_workflow the right orchestration point for
provenance:
before the write, enough resolved scientific context is available from
IndexConfigand the computed dataset;after the write, output file metadata and checksum can be collected;
the feature stays tied to the real workflow instead of being spread through lower-level helpers.
Recommended implementation shape#
Create a small dedicated module:
src/icclim/provenance.py
Suggested helpers:
collect_run_context(...)collect_software_context()collect_git_context()describe_input_path(path)describe_output_path(path)collect_execution_context(dataset)build_provenance_bundle(...)write_provenance_json(path, bundle)
Keep these helpers descriptive, not framework-heavy. The scientific
workflow should remain readable from the call site in main.py.
Initial integration steps#
Phase 1 should be deliberately small.
Add
src/icclim/provenance.pywith the data-collection helpers.Extend
_run_index_workflowso that whenout_fileis provided:a provenance bundle is built from the normalized request, resolved
IndexConfig, the result dataset and the output path;the NetCDF dataset gets compact provenance attributes before write;
the sidecar JSON is written after the NetCDF file is written.
Keep provenance optional for in-memory-only API calls with no
out_file.Do not add a new public parameter in phase 1 unless it is strictly needed.
Remaining extensions#
The first phase is deliberately conservative. Useful next extensions are:
extend the same provenance path to
icclim.indicesoutput writes;distinguish explicit user parameters from resolved defaults more fully;
record richer bootstrap routing decisions in the sidecar;
record stronger threshold semantics for compound and bounded cases;
add typed scientific warnings when a fallback route is selected.
Schema guidance#
The JSON schema should stay explicit and stable. A practical shape is:
{
"schema_version": 1,
"run_context": {},
"software": {},
"git": {},
"inputs": [],
"outputs": {},
"user_parameters": {},
"resolved_parameters": {},
"execution": {},
"warnings": []
}
Prefer explicit keys over opaque blobs. Downstream tools should not need to scrape free-form text to reconstruct a run.
Guardrails#
Hash local files only below a configurable size threshold.
Record a filtered set of environment variables, not the full process environment.
Treat missing git metadata as normal when running from an installed package or export.
Do not fail the climate-index run if provenance collection is partial.
Emit typed warnings when scientifically important defaults are used implicitly.
Tests to add#
Unit coverage should include:
sidecar JSON written next to a NetCDF output;
expected top-level sections present;
git metadata present in a repository and absent gracefully otherwise;
key package versions recorded;
user parameters and resolved parameters both present;
bootstrap routing recorded for a bootstrap workload;
SLURM metadata captured when corresponding environment variables are set;
large-file hashing fallback behaves as expected.
Scientific regression coverage should include at least one percentile bootstrap case to verify that provenance captures:
threshold class;
reference period;
calendar choices;
bootstrap route chosen by the runtime.
What was learned from idownscale#
The idownscale repository currently contains useful workflow
reconstruction notes and explicit entrypoints, but not a first-class
provenance module that can be reused directly here.
The main transferable lesson is architectural rather than code-level: keep one visible orchestration entrypoint, and record enough information there that a later engineer can reconstruct the run without hidden shell history.