--- title: "YAML validation: required keys and types" author: "Package cre.dcf" output: rmarkdown::html_vignette: toc: true number_sections: true vignette: > %\VignetteIndexEntry{YAML validation: required keys and types} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r setup, include=FALSE} knitr::opts_chunk$set(echo = TRUE, message = FALSE, warning = FALSE) library(cre.dcf) library(yaml) ``` ## Purpose This vignette illustrates the internal validation mechanism used to ensure that configuration files loaded from YAML are both complete and type-consistent with the model’s expectations. Such validation is essential for reproducibility: it guarantees that any downstream computation of discounted-cash-flows relies on a syntactically correct and semantically coherent configuration object. From a methodological perspective, strict configuration validation contributes to: Model reliability – early detection of malformed input values (e.g., string where numeric expected). Scientific transparency – enforcement of explicit parameter names and units. Reproducible computation – prevention of silent coercion errors that would bias model outputs. The example below first validates a correct configuration, then deliberately introduces an error to verify that the control mechanism fails safely and predictably. ## 1. Load and validate a correct YAML configuration ```{r} ## 1. Load and validate a correct YAML configuration # 1.1 Locate and parse a reference configuration file path <- system.file("extdata", "preset_core.yml", package = "cre.dcf") stopifnot(nzchar(path)) cfg <- yaml::read_yaml(path) stopifnot(is.list(cfg), length(cfg) > 0) # 1.2 Validate structure and types # cfg_validate() throws an error if invalid; otherwise it returns (optionally invisibly) # a configuration list that is deemed structurally consistent. validated_cfg <- cre.dcf::cfg_validate(cfg) cat("✓ Validation successful: configuration passed all structural and type checks.\n") # 1.3 For illustration, display a compact excerpt of the validated configuration. # Some implementations of cfg_validate() return cfg invisibly; others may return NULL. # We therefore fall back to the original cfg if needed. cfg_to_show <- if (is.list(validated_cfg) && length(validated_cfg) > 0L) { validated_cfg } else { cfg } cat("\nExcerpt of (validated) configuration structure:\n") utils::str(cfg_to_show[1:10], max.level = 1) ``` The call to cfg_validate() ensures, among other things, that: purchase_year is an integer-like scalar, numerical parameters such as index_rate, entry_yield, acq_cost_rate, or exit_yield_spread_bps lie in appropriate ranges, mandatory blocks (discount-rate specification, debt structure, leases) are present and correctly typed. Any violation triggers an error at this stage, before the configuration is used to construct cash-flow tables via run_case(). ## Deliberate type violation and controlled failure To test the robustness of the validation mechanism, we now introduce an explicit type error into a copy of the configuration. The field purchase_year is expected to be an integer-like scalar; replacing it by a character string should therefore cause cfg_validate() to fail. ```{r} ## 2. Deliberate type violation and controlled failure # 2.1 Clone configuration and introduce a deliberate type error: # purchase_year must be integer-like; we turn it into a character string. bad_cfg <- cfg bad_cfg$purchase_year <- "2020" # invalid type: character instead of integer/numeric # 2.2 Attempt validation and capture the expected error caught <- FALSE err_msg <- NULL tryCatch( { cre.dcf::cfg_validate(bad_cfg) }, error = function(e) { caught <<- TRUE err_msg <<- e$message } ) # 2.3 Assert that the failure mechanism was triggered stopifnot(caught) cat("\nExpected validation failure caught:\n") cat(err_msg, "\n") cat("\n✓ Error successfully detected: invalid type for 'purchase_year' was blocked at validation stage.\n") ``` ## Interpretation and theoretical significance Rigorous configuration validation is not a mere programming convenience; it reflects a scientific norm of model governance. In computational finance and quantitative geography alike, parameter schemas play a role analogous to measurement protocols in laboratory sciences: they codify the expected dimensionality and semantic type of each variable. In the context of a discounted-cash-flow engine such as cre.dcf, this mechanism ensures: - Epistemic reproducibility – identical YAML input always yields an equivalent model object. - Comparability across simulations – variations in outputs stem solely from deliberate parameter changes, not from hidden type coercions. - Auditability – external reviewers can trace parameter validity without inspecting internal code.