Provenance contract =================== What `fresh-fvsbc` records for every run, so that a number in a paper can be traced to what produced it. This contract is `fresh-fvsbc`'s own design. It is not read from FVS. The three external facts it depends on are verified: FVS writes the variant and version into `FVS_Cases` (see :doc:`outputs`); the keyword file name is recorded there too; and the build's inputs are pinned (see ADR 0001). Why it exists ------------- The project's users include reviewers and readers of published results, who need to know which variant, which source revision, and which keyword set produced a number. `notes/scope.md` names that need, and `AGENTS.md` states the rule: record the provenance of every run. What a run records ------------------ A record has these fields. .. list-table:: :header-rows: 1 :widths: 26 74 * - Field - What it is * - ``fresh_fvsbc_version`` - The `fresh-fvsbc` version that ran * - ``pyfvs_commit`` - The commit of the pinned `UBC-FRESH/PyFVS` fork * - ``fvs_source_commit`` - The commit of the FVS source submodule that the fork pins * - ``variant`` - The variant built and run, which for this project is ``bc`` * - ``variant_list`` - The full variant list the build produced, so a mistaken build is visible * - ``bec`` - The validated BEC the run used, such as ``CAR IDFdk3/01`` * - ``qmd`` - The expansion-weighted initial QMD, in centimetres * - ``qmd_min`` - The bundle's minimum QMD, when it declares one * - ``ba`` - The expansion-weighted initial basal area, in square metres per hectare * - ``ba_min`` - The bundle's minimum BA, when it declares one * - ``tsa`` - The TSA the run was checked against, when one was supplied * - ``calibration_id`` - The calibration bundle the run used, when it used one * - ``keyword_set_hash`` - A hash of the keyword set, canonically serialized * - ``treelist_hash`` - A hash of the tree-list input, canonically serialized * - ``case_id`` - The ``CaseID`` from ``FVS_Cases`` * - ``run_datetime`` - The ``RunDateTime`` from ``FVS_Cases`` * - ``random_seed`` - The seed, when the run used one. FVS exposes ``RANNSEED`` The two hashes are of a canonical serialization, not of a file. A file hash changes with a trailing newline or a column width, and it would then say a run differed when it did not. Where it lives -------------- - In memory, on the result object that a run returns. - On disk beside the outputs, as JSON, when the caller asks for it. - In the changelog or the close-out report, only as a citation. A raw record does not belong in a tracked file when it names a local path. Contract rules -------------- 1. A run that cannot record its provenance is a failure. Provenance is not optional, and it is not added afterwards. 2. The record names commits, not versions, for the two pinned inputs. A version can be republished; a commit cannot. 3. ``variant_list`` is recorded even though the project builds one variant, because a build that quietly produced a different variant is a real failure mode and this is what makes it visible. 4. The record carries no credential, no personal path, and no raw data. `AGENTS.md` states the rule, and `scripts/check_workflow.py` rejects the mechanical cases. Not verified ------------ - **Answered: PyFVS exposes the built variant list at run time.** `pyfvs.list_variants()` returns each variant with the module it would import and a status, and it returned ``{'BC': {'lib': 'pyfvs.fvsbc', 'status': 'OK'}}`` in this project's build. The status is what makes a mistaken build visible, so the record's list is built by refusing a variant whose status is not `OK`. - **Answered within a bound: `RANNSEED` controls the variation these runs show.** Two runs of one case with the seed fixed produced byte-identical summaries, and changing the seed alone changed one value in one period. So the seed is the control, and no other source showed itself. What that does not establish is that no other source exists: one that varies over a longer timescale than two runs a second apart, or one that needs more cycles or more plots to appear, would not have shown up here.