Three related validation/message problems, verified against current main:
1. as_forecast_sample() / as_forecast_quantile() accept non-numeric observed/predicted
as_forecast_sample(data.frame(
observed = as.character(c(5, 5, 5)),
predicted = as.character(c(4, 5, 6)),
sample_id = 1:3, model = "m1"
))
succeeds (returns a forecast_sample object). The failure only surfaces later in score(), as one warning per metric, e.g.:
! Computation for `crps` failed. Error: Assertion on 'observed' failed: Must be of type 'numeric', not 'character'.
and score() returns a 1-row table with only a model column. Identical behaviour for as_forecast_quantile() with character columns (8 per-metric warnings). By contrast, as_forecast_binary() and as_forecast_point() error immediately at validation time.
Cause: assert_forecast.forecast_sample() (R/class-forecast-sample.R:59-66) only checks sample_id column presence plus generic checks, and assert_forecast.forecast_quantile() (R/class-forecast-quantile.R:82-90) only asserts quantile_level is numeric — neither checks the types of observed/predicted, unlike the binary/point methods which call check_input_binary()/check_input_point(). The same gap exists in assert_forecast.forecast_multivariate_sample() (R/class-forecast-multivariate-sample.R:85-120); the multivariate point method already validates via check_input_point().
2. Quantile rounding warning says digits = 10 but code rounds to 9 digits
R/class-forecast-quantile.R:61-69: the warning emitted by as_forecast_quantile() for near-duplicate quantile levels says "we're going to run round(x, digits = 10)" but the code executes round(data$quantile_level, digits = 9). Behavioural proof: input level 0.9999999994 (representable at 10 digits) came out as 0.999999999 — 9-digit rounding was applied. The message also has an unclosed parenthesis: "(run diff(...) to see this.".
3. get_pit_histogram.forecast_quantile(): broken warning and fallback that never happens
R/class-forecast-quantile.R:249-254: cli_warn() is called with two unnamed strings, so the second sentence ("The PIT histogram will be based on the quantiles present in the forecast.") lands in rlang's class parameter instead of the message — the user only sees "Some requested quantiles are missing in the forecast." And the advertised fallback never happens:
get_pit_histogram(fq, num_bins = 7, by = "model") on example_quantile returns a 0-row data.table (all rows dropped by forecast[quantile_level %in% quantiles]).
- Partially-present
breaks = c(0.25, 0.33, 0.5) produces 4 "longer object length is not a multiple of shorter object length" warnings and silently wrong densities (values recycled, e.g. bin [0.25,0.33) density 4.59 for a bin with no coverage data).
Intended fix (maintainer decisions)
- Add
checkmate::assert_numeric() checks for observed and predicted to the sample and quantile assert_forecast() methods, and extend the same check to the multivariate sample method (multivariate point is already covered).
- Fix the warning message to say
digits = 9 (keep the code at 9 — rounding to 10 digits would fail to collapse diffs of exactly 1e-10) and close the dangling parenthesis.
- Fix the
cli_warn() call so both lines display, and make the advertised fallback actually happen: keep the requested quantiles that are present in the forecast; if none besides 0/1 survive, fall back to all present quantiles. Compute diffs after this adjustment so bins/mids/densities stay aligned.
Part of the bug audit in #1189.
Three related validation/message problems, verified against current main:
1.
as_forecast_sample()/as_forecast_quantile()accept non-numericobserved/predictedsucceeds (returns a
forecast_sampleobject). The failure only surfaces later inscore(), as one warning per metric, e.g.:and
score()returns a 1-row table with only amodelcolumn. Identical behaviour foras_forecast_quantile()with character columns (8 per-metric warnings). By contrast,as_forecast_binary()andas_forecast_point()error immediately at validation time.Cause:
assert_forecast.forecast_sample()(R/class-forecast-sample.R:59-66) only checkssample_idcolumn presence plus generic checks, andassert_forecast.forecast_quantile()(R/class-forecast-quantile.R:82-90) only assertsquantile_levelis numeric — neither checks the types ofobserved/predicted, unlike the binary/point methods which callcheck_input_binary()/check_input_point(). The same gap exists inassert_forecast.forecast_multivariate_sample()(R/class-forecast-multivariate-sample.R:85-120); the multivariate point method already validates viacheck_input_point().2. Quantile rounding warning says
digits = 10but code rounds to 9 digitsR/class-forecast-quantile.R:61-69: the warning emitted by
as_forecast_quantile()for near-duplicate quantile levels says "we're going to runround(x, digits = 10)" but the code executesround(data$quantile_level, digits = 9). Behavioural proof: input level0.9999999994(representable at 10 digits) came out as0.999999999— 9-digit rounding was applied. The message also has an unclosed parenthesis: "(rundiff(...)to see this.".3.
get_pit_histogram.forecast_quantile(): broken warning and fallback that never happensR/class-forecast-quantile.R:249-254:
cli_warn()is called with two unnamed strings, so the second sentence ("The PIT histogram will be based on the quantiles present in the forecast.") lands in rlang'sclassparameter instead of the message — the user only sees "Some requested quantiles are missing in the forecast." And the advertised fallback never happens:get_pit_histogram(fq, num_bins = 7, by = "model")onexample_quantilereturns a 0-row data.table (all rows dropped byforecast[quantile_level %in% quantiles]).breaks = c(0.25, 0.33, 0.5)produces 4 "longer object length is not a multiple of shorter object length" warnings and silently wrong densities (values recycled, e.g. bin [0.25,0.33) density 4.59 for a bin with no coverage data).Intended fix (maintainer decisions)
checkmate::assert_numeric()checks forobservedandpredictedto the sample and quantileassert_forecast()methods, and extend the same check to the multivariate sample method (multivariate point is already covered).digits = 9(keep the code at 9 — rounding to 10 digits would fail to collapse diffs of exactly 1e-10) and close the dangling parenthesis.cli_warn()call so both lines display, and make the advertised fallback actually happen: keep the requested quantiles that are present in the forecast; if none besides 0/1 survive, fall back to all present quantiles. Computediffsafter this adjustment so bins/mids/densities stay aligned.Part of the bug audit in #1189.