flowchart LR
A["raw array<br/>+ affine"] --> B["typed object<br/>NeuroVec / NeuroVol"]
B --> C["operation<br/>series_roi · temporal_snr · searchlight_apply"]
C --> D["typed result<br/>+ Receipt (.provenance)"]
D --> E["file<br/>.nii.gz + neuroim/receipt/v1: extension"]
E --> F["typed object again<br/>read_image → .provenance rehydrated"]
F -. "audit / chain / reduce" .-> C
Provenance
How .provenance is produced, chained, and rehydrated across the file boundary.
What it is
Provenance in neuroim is the policy by which every typed result carries a Receipt describing what produced it, the spatial frame it lives in, and — when relevant — the chain of prior receipts that fed it. It is also the policy by which that information survives a write/read cycle through .nii.gz and a pickle through multiprocessing.Pool.
The loop is the point: a value that leaves the library as a .nii.gz re-enters it with the same Receipt, so the next operation can chain, audit, or reduce against a frame it can verify — not one it has to trust.
Invariants
- Every typed analysis output has
.provenance.ROIExtractionResult,SearchlightResult,DenseNeuroVolproduced by a reduction or filter, andParcelEffectResultall carry aReceipt. - Identical inputs → identical receipts. Two
temporal_snrcalls with the same BOLD and mask produce equalprovenanceobjects (moduloneuroim_version). - Chained operations chain receipts. When
gaussian_blurconsumes a volume that already has.provenance, the result records the upstream method in itsmethod_name(e.g."temporal_snr+gaussian_blur") and threads the predecessor. - Round-trip safe through pickle. A pickled-then-unpickled result produces equal
provenance. Backed by scenario S08. - Round-trip safe through
.nii.gz.to_nibabel()+nib.save()is the receipt-preserving write path today;write_volgaining the same embedding is tracked asneuroim-python-ur0and is the single change that will retire this note.read_imagethen rehydrates the JSON Receipt from the NIfTIcommentextension. Backed by scenario S05. - Spec-conformant. The on-disk format is
spec/receipt-nifti-extension.md, version v1. Future format changes use a new prefix; readers that know only v1 silently ignore unknown prefixes.
What survives the file
- The eight Receipt fields, byte-identical.
- The version prefix (
neuroim/receipt/v1:). - The JSON body, sorted-key, UTF-8 encoded.
What doesn’t survive the file (yet)
- Full operation-parameter blobs.
gaussian_blur’ssigma,resample’sorder,searchlight_apply’smethodreference are recorded in the in-process chain but the v1 receipt records only the eight headline fields on disk. A future v2 prefix is reserved for richer payloads; readers that know only v1 are expected to ignore unknown prefixes without raising. - Numeric content hashes. v1 hashes the frame, not the bytes. Recomputing a
Receiptfrom a written volume’s numeric payload is not part of the spec. - Cross-file references. A Receipt records
input_space_hashandmask_hash, not the paths of the source files. The hashes are the join key.
What it refuses
provenance is data and never raises by itself. The refusals it enables:
verify.assert_same_space(a, b)andverify.assert_same_mask(a, b)raiseValueErrorwhen two results/receipts disagree on space or mask;verify.diff_receipts(a, b)returns the structured diff without raising.read_imagerefuses to silently treat a foreigncommentextension as a Receipt — theneuroim/receipt/v1:prefix is mandatory.read_imagerefuses to coerce a futureneuroim/receipt/v2:payload as v1.
What it doesn’t do
- It is not a journal. Provenance records the operation that produced a carrier (plus its chained predecessors). It is not an audit log of every method call ever applied to a buffer.
- It is not a manifest. No paths, no host names, no timestamps. The Receipt identifies what kind of thing was done with what spatial inputs, not where the file lived.
- It is not authenticated. Two different processes producing the same operation on the same inputs produce indistinguishable receipts. Treat receipts as misalignment alarms, not as signatures.
See also
- Start 05 — Round-trip — the on-ramp’s encounter with the file boundary.
- Receipt — the eight fields, in detail.
- Spec: Receipt v1 — the public on-disk contract.
- Scenarios: S05, S08, S09, S13, S14.