YAML validation: required keys and types

Package cre.dcf

1 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.

2 1. Load and validate a correct YAML configuration

## 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:
utils::str(cfg_to_show[1:10], max.level = 1)
## 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().

3 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.

## 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:
cat(err_msg, "\n")
## 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.

4 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: