Author: Package cre.dcf

# 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.05
    ##  $ 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

Configuration validation is more than a coding convenience. It helps keep runs comparable and makes input errors visible early.

In `cre.dcf`, this helps ensure:

- reproducibility: the same YAML input yields the same type of model object;

- comparability across simulations: output changes come from explicit parameter changes, not silent coercions;

- auditability: reviewers can check input validity without reading the engine internals.