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
# 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")## ✓ Validation successful: configuration passed all structural and type checks.
# 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")##
## Excerpt of (validated) configuration structure:
## List of 10
## $ purchase_year : int 2025
## $ horizon_years : int 10
## $ index_rate : num 0.01
## $ entry_yield : num 0.045
## $ acq_cost_rate : num 0.07
## $ exit_yield_spread_bps : int 25
## $ exit_transaction_costs:List of 2
## $ ltv_base : chr "price_di"
## $ capitalized_fees : logi TRUE
## $ arrangement_fee_pct : num 0
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().
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.
## 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")##
## Expected validation failure caught:
## Assertion on 'cfg$purchase_year' failed: Must be of type 'integerish', not 'character'.
cat("\n✓ Error successfully detected: invalid type for 'purchase_year' was blocked at validation stage.\n")##
## ✓ Error successfully detected: invalid type for 'purchase_year' was blocked at validation stage.
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.