Closes the last blocked test in the suite. Owner ruled both halves of the open question yes on 2026-07-30. `cog_revenue()` gains `revenue_concept`, mirroring `expenditure_concept`, with Census's two published concepts defined as crosswalk `revenue_subtype` sets rather than item-code prefixes: general = own_source + federal + state + local_aid (the default) total = general + utility + liquor_store + insurance_trust The manual defines the first by subtracting the other three from the second (4.3), so both are computable only once all four families are named -- which cog_pipeline#79 does. Insurance trust now includes the employee-retirement X codes (X01/X02/X05/X08) alongside the Y codes. - inst/sql: revenue_long / revenue_long_harmonized carry EVERY revenue subtype; the concept narrows in R via the existing subtype_scope machinery, exactly as expenditure_concept narrows spending_long. - cog_explain() now prints each verb's OWN concept. It previously printed `expenditure_concept` unconditionally, so a cog_revenue() caller was told "Concept: primary" -- a spending concept their result has nothing to do with. - Fixture regenerated at pipeline_commit aadb46b (330 crosswalk rows). Corrected two stale expectations in the blocked test while un-skipping it. It asserted X01+X04+X05+X08 and omitted X02, which applies to state governments and is nonzero for Wisconsin; X04 is an exhibit code for an INTRAgovernmental transfer that Census's own "Total Emp Ret Rev" excludes. Verified against that Census field: the right set is X01+X02+X05+X08 = $2,283,883k, exactly. And its expected `total` of $33,377,093k predated the Y codes being classified -- complete Total Revenue for WI FY2012 is $34,881,961k (general 31,338,293 + Y 1,259,785 + X 2,283,883). Behaviour change worth knowing: `general` is now STRICT Census General Revenue, so utility and liquor store revenue leave the default. Measured on the fixture that is 15.9% of what cog_revenue() returned for cities, vs 1.2% for states and 1.7% for counties. Suite: 716 pass / 0 fail / 0 skip -- the first time this package has had no skipped tests. Closes #12
140 lines
7.3 KiB
R
140 lines
7.3 KiB
R
# Madison walkthrough audit -- finding F-014. Tracked as uscogdata#12.
|
|
# See docs/walkthroughs/FINDINGS.md in cog_explorer.
|
|
#
|
|
# cog_revenue()'s flow_prefixes = c("T","A","U","B","C","D") never returns
|
|
# item-code prefix X (Employee Retirement) or Y (other Insurance Trust). Per
|
|
# Census's standard identity, Total Revenue = General + Utility + Liquor Store +
|
|
# Insurance Trust Revenue, and Employee Retirement System contributions and
|
|
# earnings ARE the Insurance Trust Revenue component -- so prefix X sits inside
|
|
# a published Census revenue concept exactly the way I89 sits inside Census's
|
|
# Direct Expenditure concept (finding F-012).
|
|
#
|
|
# RULED 2026-07-30. `revenue_concept = c("general", "total")` mirrors
|
|
# `expenditure_concept`, and the two values are Census's two published revenue
|
|
# concepts, related by the manual's own identity (section 4.3, which defines
|
|
# the first by SUBTRACTING from the second):
|
|
#
|
|
# Total Revenue = General + Utility + Liquor Store + Insurance Trust
|
|
#
|
|
# so `general` is the four general subtypes (own_source/federal/state/
|
|
# local_aid) and `total` is every revenue subtype. Naming utility (A91-A94)
|
|
# and liquor store (A90) separately is what makes BOTH computable -- before
|
|
# cog_pipeline#79 they sat in own_source, so the default was really
|
|
# "General + Utility + Liquor", a concept Census does not publish.
|
|
#
|
|
# Fixture reproducibility: Madison's own X-prefix revenue (FY1970-FY1986,
|
|
# $15,098,000 nominal, $0 thereafter) is outside the bundled fixture's year
|
|
# window (2011/2012/2019/2020), so the same invariant is asserted on Wisconsin
|
|
# state government FY2012, where the fixture carries nonzero X01/X02/X05/X08.
|
|
|
|
test_that("cog_revenue() can return Census Total Revenue including Insurance Trust (prefix X)", {
|
|
wi_state <- "550000227544" # WISCONSIN (state government)
|
|
|
|
# Revenue-shaped Employee Retirement codes, read from the RAW corpus rather
|
|
# than through cog_revenue(), which is the filter under test:
|
|
# X01/X02 employee contributions, X05 contributions from other governments,
|
|
# X08 total earnings on investments.
|
|
#
|
|
# X04 and X06 are deliberately NOT in this set, though an earlier draft of
|
|
# this test included X04. Both are exhibit codes for INTRAgovernmental
|
|
# transfers (the administering government paying into its own fund), which
|
|
# X05's own definition excludes by name. Census agrees: its computed "Total
|
|
# Emp Ret Rev" for this government-year is exactly the four codes below.
|
|
x_revenue <- wt_raw_amt(wi_state, 2012L, codes = c("X01", "X02", "X05", "X08"))
|
|
expect_equal(x_revenue, 2283883) # 615,835 + 245,083 + 560,382 + 862,583
|
|
|
|
# The Y-prefix insurance trust revenue (unemployment + workers comp), which
|
|
# is the other half of the same Census concept.
|
|
y_revenue <- wt_raw_amt(wi_state, 2012L, codes = c("Y01", "Y11"))
|
|
expect_equal(y_revenue, 1259785)
|
|
|
|
general <- cog_revenue(govid = wi_state, years = 2012L)
|
|
expect_equal(attr(general, "provenance")$revenue_concept, "general")
|
|
expect_equal(sum(general$amt_nominal), 31338293000)
|
|
|
|
total <- cog_revenue(govid = wi_state, years = 2012L, revenue_concept = "total")
|
|
expect_equal(attr(total, "provenance")$revenue_concept, "total")
|
|
|
|
# total - general is the whole insurance trust leg, X and Y together.
|
|
# Asserted as a delta as well as a level so this stays correct however the
|
|
# utility/liquor families land (both are $0 for WI state in FY2012).
|
|
expect_equal(sum(total$amt_nominal) - sum(general$amt_nominal),
|
|
(x_revenue + y_revenue) * 1000)
|
|
expect_equal(sum(total$amt_nominal), 34881961000)
|
|
expect_true(all(c("X01", "X02", "X05", "X08") %in% wt_codes_included(total)))
|
|
|
|
# Sibling codes under the SAME first letter must stay out: X11/X12 are
|
|
# benefit payments (an expenditure) and X21/X30/X47 are cash and securities
|
|
# holdings (a balance-sheet stock). This is the F-018 point restated on the
|
|
# revenue side -- the split comes from the crosswalk, not from the letter X.
|
|
expect_false(any(c("X11", "X12", "X21", "X30", "X47") %in% wt_codes_included(total)))
|
|
|
|
# Every returned row still resolves to a category (cog_pipeline#79 added the
|
|
# X crosswalk rows; relaxing a prefix filter alone would have produced
|
|
# category = NA rows).
|
|
expect_false(any(is.na(total$category)))
|
|
})
|
|
|
|
test_that("revenue_concept = 'general' is the default and is strict Census General Revenue", {
|
|
wi_state <- "550000227544"
|
|
default <- cog_revenue(govid = wi_state, years = 2012L)
|
|
explicit <- cog_revenue(govid = wi_state, years = 2012L,
|
|
revenue_concept = "general")
|
|
expect_equal(sum(default$amt_nominal), sum(explicit$amt_nominal))
|
|
|
|
# General Revenue excludes utility, liquor store AND insurance trust
|
|
# revenue. WI state carries $0 of utility/liquor in FY2012, so the level
|
|
# assertion above cannot see those two -- assert the subtype scope directly.
|
|
#
|
|
# A subset, not setequal: `state` means "intergovernmental revenue FROM the
|
|
# state government" (the C codes), which a STATE government does not receive
|
|
# from itself, so it is legitimately absent here.
|
|
expect_true(all(default$revenue_subtype %in%
|
|
c("own_source", "federal", "state", "local_aid")))
|
|
expect_false(any(c("utility", "liquor_store", "insurance_trust") %in%
|
|
default$revenue_subtype))
|
|
})
|
|
|
|
test_that("utility and liquor store revenue are inside `total` and outside `general`", {
|
|
# A city, where utility revenue is material: this is the case the WI state
|
|
# baseline structurally cannot exercise. Measured on the fixture, utility +
|
|
# liquor is 15.9% of what cog_revenue() returned for type-2 governments
|
|
# before the general/total split, so this is the largest behaviour change
|
|
# the concept split introduces.
|
|
con <- uscogdata:::.ensure_session()
|
|
gov <- DBI::dbGetQuery(con,
|
|
"SELECT canonical_govid, SUM(amt) amt FROM long
|
|
WHERE year = 2012 AND type = 2 AND NOT is_aggregate
|
|
AND item_code IN ('A91','A92','A93','A94')
|
|
GROUP BY 1 ORDER BY amt DESC LIMIT 1")$canonical_govid
|
|
|
|
util_raw <- wt_raw_amt(gov, 2012L, codes = c("A90", "A91", "A92", "A93", "A94"))
|
|
expect_gt(util_raw, 0)
|
|
|
|
general <- cog_revenue(govid = gov, years = 2012L)
|
|
total <- cog_revenue(govid = gov, years = 2012L, revenue_concept = "total")
|
|
|
|
expect_false(any(c("utility", "liquor_store") %in% general$revenue_subtype))
|
|
expect_true("utility" %in% total$revenue_subtype)
|
|
expect_equal(sum(total$amt_nominal) - sum(general$amt_nominal),
|
|
util_raw * 1000 +
|
|
wt_raw_amt(gov, 2012L, codes = c("Y01", "Y11", "X01", "X02",
|
|
"X05", "X08")) * 1000)
|
|
})
|
|
|
|
test_that("revenue_concept rejects unknown values and never returns a balance row", {
|
|
expect_error(
|
|
cog_revenue("550000227544", years = 2012L, revenue_concept = "gross"),
|
|
class = "uscogdata_invalid_revenue_concept"
|
|
)
|
|
|
|
# uscogdata#25 restated for the widest revenue concept: stocks are not
|
|
# flows, and `total` must not quietly admit the X/Y/W/Z balance families.
|
|
con <- uscogdata:::.ensure_session()
|
|
balance <- DBI::dbGetQuery(con,
|
|
"SELECT item_code, category FROM summary_categories WHERE category_type = 'balance'")
|
|
total <- cog_revenue("550000227544", years = 2012L, revenue_concept = "total")
|
|
expect_false(any(total$category %in% balance$category))
|
|
expect_length(intersect(wt_codes_included(total), balance$item_code), 0L)
|
|
})
|