From a4eb80d823751cdeec1af2b101f4865c862b6c2b Mon Sep 17 00:00:00 2001 From: Jared Knowles Date: Mon, 27 Jul 2026 12:06:28 -0400 Subject: [PATCH] feat: cog_explain() prints the expenditure concept and direct-suppressed flag (I1) .print_provenance() printed "Basis:" but nothing about Direct vs Total -- the most consequential switch this branch adds to cog_spending() was invisible in the package's designated "what am I looking at" verb. Add a "Concept: direct|total ()" line next to Basis, and surface a cli warning when provenance$expenditure_concept_direct_suppressed is TRUE (see the C1 fix), so the suppressed-Direct case is visible in the human-readable explain output, not just in the structured provenance. --- R/explain.R | 15 +++++++++++++++ tests/testthat/test-explain.R | 31 +++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+) diff --git a/R/explain.R b/R/explain.R index 2f2d44b..f7dd5b9 100644 --- a/R/explain.R +++ b/R/explain.R @@ -60,6 +60,21 @@ cog_explain <- function(result, format = c("print", "list")) { cli::cli_text("Basis: {prov$basis}{note}") } + if (!is.null(prov$expenditure_concept)) { + concept_note <- if (!is.null(prov$expenditure_concept_note) && + !is.na(prov$expenditure_concept_note)) { + sprintf(" (%s)", prov$expenditure_concept_note) + } else { + "" + } + cli::cli_text("Concept: {prov$expenditure_concept}{concept_note}") + if (isTRUE(prov$expenditure_concept_direct_suppressed)) { + cli::cli_alert_warning( + "Direct leg unavailable for at least one requested (year, category) -- affected rows report intergovernmental dollars alone, not Direct + IG. See each row's notes." + ) + } + } + cli::cli_h2("Codes observed") codes <- prov$codes_summed$observed if (length(codes) == 0L) { diff --git a/tests/testthat/test-explain.R b/tests/testthat/test-explain.R index e824807..fc8f7d3 100644 --- a/tests/testthat/test-explain.R +++ b/tests/testthat/test-explain.R @@ -70,6 +70,37 @@ test_that("cog_explain prints a Suggestions section when the provenance has one" expect_true(grepl("re-run with recipe", txt)) }) +test_that("cog_explain prints the expenditure concept (I1)", { + skip_if_no_corpus() + d <- cog_spending("010000226085", years = 2019, category = "Police") + t <- cog_spending("010000226085", years = 2019, category = "Police", + expenditure_concept = "total") + txt_d <- paste(c( + capture.output(cog_explain(d)), + capture.output(cog_explain(d), type = "message") + ), collapse = "\n") + txt_t <- paste(c( + capture.output(cog_explain(t)), + capture.output(cog_explain(t), type = "message") + ), collapse = "\n") + expect_true(grepl("Concept: direct", txt_d)) + expect_true(grepl("Concept: total", txt_t)) +}) + +test_that("cog_explain surfaces the C1(b) direct-suppressed flag as a warning", { + skip_if_no_corpus() + t <- suppressMessages(cog_spending( + "010000226085", years = 2011, category = "Corrections", + expenditure_concept = "total" + )) + expect_true(attr(t, "provenance")$expenditure_concept_direct_suppressed) + txt <- paste(c( + capture.output(cog_explain(t)), + capture.output(cog_explain(t), type = "message") + ), collapse = "\n") + expect_true(grepl("Direct leg unavailable", txt)) +}) + test_that("cog_explain prints denominator + popyear_range + counts", { skip_if_no_corpus() with_fixture_corpus({