feat: three-concept expenditure model classified by crosswalk membership (#11)
R-CMD-check / check (push) Successful in 3m5s
R-CMD-check / check (push) Successful in 3m5s
Rewrites expenditure/revenue classification off item-code first-letter
prefixes and onto summary_categories membership (F-018: prefix Y spans
revenue, expenditure, and balance codes), and exposes
expenditure_concept = c("primary", "direct", "total") with primary as
the new default:
primary = operations + capital + assistance
direct = primary + interest + insurance_benefits (Census Direct)
total = direct + intergovernmental (M/L/Q via ig views)
- inst/sql: flow views (20-25) select by crosswalk membership;
summary_categories moves to 11- so it registers before them (DuckDB
binds view sources eagerly). The IG leg gains Q11/Q12/Q18 state
school-system payments (F-017).
- R: one subtype scope per verb call drives the verb SQL, the
harmonization exclusion count, and the complete = TRUE grid;
flow_prefixes survives only to scope recipe suggestions.
cog_geographic_rollup/cog_peer_compare accept primary|direct, still
refuse total, and now actually pass the concept through.
- Balance codes can never reach a spending or revenue result
(uscogdata#25), asserted at both view and verb level.
- Deletes the #11 skip; per the 2026-07-30 owner ruling the F-018 Y01
proof is asserted against the crosswalk, not the default
cog_revenue() call (which stays General Revenue pending #12).
Suite: 696 pass / 0 fail / 1 skip (#12, expected).
Closes #11
This commit is contained in:
@@ -19,8 +19,6 @@
|
||||
# also check the FY2022 numbers above.
|
||||
|
||||
test_that("expenditure concepts classify on spend_type, not item-code prefix", {
|
||||
testthat::skip("Blocked on uscogdata#11 (findings F-012, F-017, F-018)")
|
||||
|
||||
mad <- "552025209777" # MADISON CITY, WI
|
||||
wi_state <- "550000227544" # WISCONSIN (state government)
|
||||
|
||||
@@ -61,15 +59,54 @@ test_that("expenditure concepts classify on spend_type, not item-code prefix", {
|
||||
|
||||
# -- F-018: prefix Y splits revenue from expenditure, by spend_type ---------
|
||||
# Y01/Y02 are Insurance Trust revenue; Y05/Y06 are Insurance Trust benefit
|
||||
# payments. All four share the first letter `Y` and the spend_type
|
||||
# "Insurance Trust", so this pair of assertions is the concrete proof that
|
||||
# classification is no longer keyed on the first letter.
|
||||
# payments. All four share the first letter `Y`, so no first-letter allowlist
|
||||
# can route them. The proof that classification is crosswalk-keyed:
|
||||
# Y05 lands in `total` spending (insurance_benefits is inside `direct`),
|
||||
# while Y01 -- same prefix -- is classified `revenue` by the crosswalk and
|
||||
# therefore can never appear in a spending result.
|
||||
#
|
||||
# Per the owner's 2026-07-30 ruling (#11 DoD item 4 vs #12), cog_revenue()'s
|
||||
# DEFAULT stays Census General Revenue and so excludes insurance-trust
|
||||
# revenue; Y01's revenue-side classification is asserted against the
|
||||
# crosswalk itself, not the default call. Surfacing Y01 through an explicit
|
||||
# revenue concept argument is uscogdata#12.
|
||||
wi_revenue <- cog_revenue(govid = wi_state, years = 2019L)
|
||||
spend_codes <- wt_codes_included(wi_total)
|
||||
rev_codes <- wt_codes_included(wi_revenue)
|
||||
|
||||
expect_true("Y05" %in% spend_codes)
|
||||
expect_false("Y05" %in% rev_codes)
|
||||
expect_true("Y01" %in% rev_codes)
|
||||
expect_false("Y01" %in% spend_codes)
|
||||
expect_false("Y01" %in% rev_codes) # default = general revenue (#12 ruling)
|
||||
|
||||
con <- uscogdata:::.ensure_session()
|
||||
y_class <- DBI::dbGetQuery(con,
|
||||
"SELECT item_code, category_type, spend_subtype, revenue_subtype
|
||||
FROM summary_categories WHERE item_code IN ('Y01', 'Y05')")
|
||||
expect_equal(y_class$category_type[y_class$item_code == "Y01"], "revenue")
|
||||
expect_equal(y_class$revenue_subtype[y_class$item_code == "Y01"], "insurance_trust")
|
||||
expect_equal(y_class$category_type[y_class$item_code == "Y05"], "expenditure")
|
||||
expect_equal(y_class$spend_subtype[y_class$item_code == "Y05"], "insurance_benefits")
|
||||
})
|
||||
|
||||
test_that("no balance code or category ever reaches a spending or revenue result (uscogdata#25)", {
|
||||
# Stocks are not flows. The crosswalk's balance codes (W/X/Y/Z fund
|
||||
# balances) share first letters with flow codes, so this could never be
|
||||
# guaranteed under prefix classification; under crosswalk membership it
|
||||
# falls out structurally -- asserted here at the verb level, on a
|
||||
# government-year the fixture gives real balance rows (Wisconsin carries
|
||||
# Y07/Y08/Y21/Y61-type balances in FY2019).
|
||||
wi_state <- "550000227544"
|
||||
con <- uscogdata:::.ensure_session()
|
||||
balance <- DBI::dbGetQuery(con,
|
||||
"SELECT item_code, category FROM summary_categories WHERE category_type = 'balance'")
|
||||
expect_gt(nrow(balance), 0L)
|
||||
|
||||
spend <- cog_spending(wi_state, 2019L, expenditure_concept = "total")
|
||||
rev <- cog_revenue(wi_state, 2019L)
|
||||
|
||||
expect_false(any(spend$category %in% balance$category))
|
||||
expect_false(any(rev$category %in% balance$category))
|
||||
expect_length(intersect(wt_codes_included(spend), balance$item_code), 0L)
|
||||
expect_length(intersect(wt_codes_included(rev), balance$item_code), 0L)
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user