--- title: "API lifecycle and reproducibility contracts" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{API lifecycle and reproducibility contracts} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r setup, include=FALSE} knitr::opts_chunk$set(collapse = TRUE, comment = "#>") ``` ## Why the package has contracts `SOMevidence` treats software interfaces and evidence structures as part of reproducibility. A changed argument, default, or returned field can alter an analysis even when a function retains the same name. The package therefore ships machine-readable contracts for both exported functions and returned objects. The version 1.0.0 contracts remain the structural compatibility baseline, and the version 1.1.0 contracts remain unchanged as a historical release record. The current 1.2.0 contracts add exact default-expression records and structural contract versions for public result objects. Structural compatibility does not imply that an analysis which omits version-sensitive defaults will be numerically identical across releases. ```{r contracts} contract_path <- function(name) { system.file("extdata", name, package = "SOMevidence") } baseline_api <- utils::read.csv( contract_path("api-contract-v1.0.0.csv"), check.names = FALSE ) api_contract <- utils::read.csv( contract_path("api-contract-v1.2.0.csv"), check.names = FALSE ) api_formals <- utils::read.csv( contract_path("api-formals-v1.2.0.csv"), check.names = FALSE ) object_contract <- utils::read.csv( contract_path("object-contract-v1.2.0.csv"), check.names = FALSE ) migrations <- utils::read.csv( contract_path("object-migrations-v1.2.0.csv"), check.names = FALSE ) c(baseline_exports = nrow(baseline_api), current_exports = nrow(api_contract)) table(api_contract$lifecycle) head(object_contract[c("class", "lifecycle")]) head(migrations[c("class", "automatic")]) ``` Automated tests require all historical stable arguments to remain present as an order-preserving prefix. They also compare the current namespace, complete function formals and defaults, return classes, object components, required attributes, and selected evidence-table schemas with the 1.2.0 contracts. ## What changed in the 1.2.0 contract The current contract adds three linked safeguards: - external labels can be joined by validated sample identity, with explicit record states for absent, missing, excluded, unassigned and insufficiently replicated observations; - every public result object records `som_contract_version = "1.2.0"`, and `upgrade_som_object()` performs only deterministic migrations supported by retained evidence; and - experimental `audit_som_representation()` compares continuous topology across prespecified fit pairs through shortest-hop grid distances and optional tie-preserving neighbourhood overlap. The representation audit uses exact fit-pair and sample-pair budgets. It has no score, rank, default scientific threshold or automatic selection rule, and it cannot be passed to `assess_defensibility()` as hard-partition evidence. ## What changed in the 1.1.0 contract The current contract makes several correctness safeguards explicit: - named multi-layer inputs are aligned by sample identity or rejected; - resampling objects retain ordered sample identifiers and unique split IDs; - Ward.D2 training labels remain the `cutree()` partition, whereas new rows use an explicitly named nearest-centroid projection rule; - GMM initialization uses a recorded deterministic seed; - partition records retain the number of sample-level classes actually observed, and incomplete `k` partitions cannot enter consensus; - aligned voting can propagate labels along a connected overlap path and reports consensus-label coverage separately from assignment coverage; - pairwise auditing has a user-visible computation budget; - transfer evidence reports mapping counts and coverage; - training-constant variables are excluded from held-out distance; and - cross-model gates use method-specific evidence rather than a pooled median. Version 1.1.0 also changes the default reference set from K-means, Ward.D2 and GMM to K-means and Ward.D2. This avoids making an optional dependency and its additional model-selection step part of every default run. To reproduce the 1.0 default reference set, request it explicitly: ```r cross_models <- c("kmeans", "ward", "gmm") ``` This default change can alter fitted evidence and is therefore recorded in the versioned contract and `NEWS.md`. Reproducible analyses should pin the package version and specify the reference methods rather than relying on defaults. The top-level workflow now records requested candidate values and lightweight software provenance. Its summary reports model, consensus, warning, and failure counts without requiring users to traverse nested lists. Compact sensitivity results retain model-stage failures and warnings, and new-data mapping objects retain structured warnings. These are software and evidential safeguards. They do not turn internal validity, cross-model agreement, or transfer diagnostics into ecological truth. The repository's [validation-scope statement](https://github.com/shaowen-ye/SOMevidence/blob/main/VALIDATION_SCOPE.md) separates software verification, design-conditioned reproducibility, worked examples, and future external validation. ## Stable and experimental interfaces Stable functions cover the data contract, preprocessing, sampling design, ensemble fitting, evidence audits, transfer, and conditional decision gates. The names and positional prefix of stable 1.0.0 arguments remain supported. Removing or reordering those arguments, or withdrawing a documented object guarantee, requires a new major package version. Analysis-affecting default changes must be explicit in a versioned contract and release notes; publication workflows should still record every consequential setting directly. Four interfaces remain experimental: ```{r experimental} api_contract[api_contract$lifecycle == "experimental", c("function", "return_class", "notes")] ``` `launch_som_app()` returns a `shiny.appobj`. It can be printed in an interactive session or passed to `shiny::runApp()`, but it does not return an analysis result. `SOMevidence` adds no telemetry. In a local session, a selected file remains on the local computer; in a remotely deployed app, Shiny transfers it to that host. Its YAML export is a configuration snapshot. The exported R script can be rerun, but it becomes part of a reproducible record only when retained with the exact input, software versions, warnings, failures, and results. The sensitivity, simulation and continuous-representation audit interfaces also remain experimental because their scenario descriptions or reporting structures may evolve after broader use. ## Object boundaries are scientific boundaries The returned classes keep distinct questions apart: - `som_audit` concerns representation quality; - `som_representation_audit` concerns exact cross-fit topology concordance, not map selection or partition defensibility; - `som_partitions` and `som_consensus` concern analysis-scope hard-partition stability; - `som_cross_comparison` concerns algorithmic agreement; - `som_transfer_audit` concerns held-domain behaviour; - `som_external_assessment` concerns post hoc agreement with labels excluded from training; and - `som_defensibility` records an analyst-specified conditional decision. No object is a certificate of ecological truth. Cross-model agreement is not a leaderboard, external-label agreement is not classification accuracy, missing evidence remains visible, and insufficient evidence may lead to abstention. A `supported` decision means only that the stated analyst-specified evidence requirements and structural checks passed for that workflow. It does not prove that discrete ecological types exist. A continuous gradient illustrates the boundary: imposing a fixed `k` can yield similar partitions across resamples, starts, or algorithms even though the underlying structure contains no discrete classes. Stability and cross-model agreement therefore remain conditional evidence, not a test of discreteness. ## Reporting an analysis Archive the package version, session information, analysis script, sampling design, and gate settings with every analysis: ```{r report-version} packageVersion("SOMevidence") sessionInfo() ``` For work intended to support a publication, also retain the exact data provenance, stable sample identifiers, preprocessing specification, random seeds, model failures, warnings, model budget, and API contract version used by the analysis. The structural object contract is distinct from analysis provenance. It tells software which fields are present; it does not identify the package build, algorithm version or scientific choices that created those fields. If an older object lacks evidence required by the current contract, recomputation is safer than migration: ```r upgraded <- upgrade_som_object(saved_result) ```