cog_revenue() has no revenue concept and permanently excludes Insurance Trust revenue (prefix X/Y) #12
Closed
opened 2026-07-29 00:05:28 -04:00 by jared
·
1 comment
No Branch/Tag Specified
main
ci/mirror-canonical-tags
chore/release-47-badges-mirror-pr
docs/readme-perf-remeasure-56
feat/pagination-search-balances-57
feat/duckdb-threads-60
feat/cohort-predicates-58
fix/windows-backslash-paths
ci/mirror-to-github
ci/github-actions-matrix
feat/public-release-0.3.0
chore/fixture-sb203
ci/apt-https
fix/pushdown-pagination
feat/all-categories-37
fix/partial-coverage-signposting-9
fix/schema-v7
fix/cog-categories-balance-subtype
feat/cog-balances-25
feat/revenue-concepts-12
feat/expenditure-concepts-11
feat/coverage-disclosure-13
feat/complete-argument-18
fix/kodor-batch-14-15-16
fix/all-scoped-series-breaks-19
fix/regen-fixture-corpus-18
test/walkthrough-findings
feat/expenditure-concept
fix/3-url-trailing-slash
feat/phase-r3-signposting
fix/fixture-option-b-aggregates
feat/phase-r2-harmonization
feat/phase-r1-forward
feat/cog-gov-search-basket-mode
v0.4.0
Labels
Clear labels
kodor
kodor/feature-proposal
kodor/fix
kodor/needs-review
kodor/triaged
madison-walkthrough
severity/high
severity/low
severity/medium
south-guide
verdict/defect
verdict/definitional
kodor
kodor/feature-proposal
kodor/fix
kodor/needs-review
kodor/triaged
Kodor should process this issue
Kodor has written a feature proposal
Kodor should implement a fix (assigned to Kodor)
Kodor's work or failure needs Jared's review
Kodor has already triaged this issue (skip)
Surfaced while building the client-facing Southern API guide
needs
human
Cannot move without a person -- a decision, a check an agent cannot make, something outside the repo
origin
client
Came from a client ask
origin
obligation
Created by a change elsewhere
origin
review
Came from human review
origin
roborev
Promoted from a roborev finding
type
chore
Maintenance with no behaviour change
type
debt
Owed work -- docs, tests, cleanup a change obligated
type
decision
Needs a decision before work can proceed
type
defect
Something is wrong
type
feature
New capability
ws
api
Query verbs and results
ws
corpus
Corpus, mirror, provenance
ws
docs
Vignettes and guides
Assign a task to kodor
Kodor thinks this needs a feature.
Kodor should fix this
Kodor thinks the user is ready to review this.
Kodor is done with this issue.
Milestone
No items
No Milestone
Projects
Clear projects
No projects
No Assignees
Notifications
Due Date
No due date set.
Dependencies
No dependencies set.
Reference: Civilytics/uscogdata#12
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Filed from the Madison walkthrough audit (
cog_explorer/docs/walkthroughs/FINDINGS.md, 2026-07-28). Verdict: definitional.Root cause
cog_revenue()'sflow_prefixes = c("T", "A", "U", "B", "C", "D")(R/revenue.R:23, via therevenue_longview) never returns item-code prefixX(Employee Retirement) orY(other Insurance Trust). Per Census's standard accounting identity, Total Revenue = General Revenue + Utility Revenue + Liquor Store Revenue + Insurance Trust Revenue, and Employee Retirement System contributions/earnings are the Insurance Trust Revenue component — so prefixXsits inside a published Census revenue concept the same wayI89sits inside Census's Direct Expenditure concept.Filed separately from the expenditure-concept issue for one reason: unlike
cog_spending(),cog_revenue()has no argument that names a Census concept — norevenue_conceptmirroringexpenditure_concept. Its documentation promises "revenue by category," not a named Census total, so there is no explicit contradiction between a documented claim and the corpus's broader concept. Closing this therefore needs a design decision the owner has not yet made (the settled three-concept resolution covers expenditure only), which is why it is not folded into that work.Findings resolved
cog_revenue()permanently excludes item-code prefixX(Employee Retirement contributions and earnings), which is real revenue for Madison FY1970-FY1986 and part of Census's Total Revenue conceptReproduction (verbatim from FINDINGS.md, verified against the live corpus)
Why it matters
Materiality for Madison specifically is modest — roughly 1-2% of revenue in its highest years, zero after 1986 — and this document's own FY2022 checkpoint is unaffected. It is named because it is the same class of gap as the interest exclusion in
cog_spending(): a published Census revenue concept that this package's public interface cannot reach at all. Anyone reconciling this corpus against Census's published Total Revenue for a state government or a large retirement-system-operating city will be short by the entire Insurance Trust Revenue component with no signal in the return value.A second, independent gap compounds it:
summary_categorieshas zero rows for prefixXorYat all, so relaxingflow_prefixesalone would produce rows withcategory = NArather than a categorised result — the same fix the pipeline crosswalk-coverage issue already needs for a different code family.Definition of done
revenue_conceptparameter mirroring the settledexpenditure_conceptmodel — plausiblygeneral(today's behaviour) vs.total(adding Insurance Trust and any other component of Census's Total Revenue identity). Whatever the names, today's behaviour stays reachable and stays the default unless the owner rules otherwise.spend_typecolumn, not first-letter prefixes —X11/X12(benefit payments, an expenditure) andX21/X30/X42/X44/X47(cash and securities, a balance-sheet stock) must not be swept in withX01/X04/X05/X08, and prefixYsplits revenue (Y01/Y02) from expenditure (Y05/Y06) under one letter. Same root cause as the expenditure-concept issue.cog_revenue()'s documentation states that it returns General/Utility/Liquor-Store revenue only and never Insurance Trust revenue, so the returned figure is not Census's Total Revenue.tests/testthat/test-revenue-concept-insurance-trust.R→test_that("cog_revenue() can return Census Total Revenue including Insurance Trust (prefix X)", ...). Against the bundled fixture it asserts Wisconsin state FY2012 revenue under the new concept equals $33,377,093,000 — today's$31,338,293,000plusX01(615,835) +X05(560,382) +X08(862,583) thousands, each read from the raw corpus rather than through the verb under test — and thatX11/X21/X30/X47are not included. Remove theskip()on line 1 of the test body to activate.(Madison's own FY1970-FY1986 X-prefix revenue, $15,098,000 nominal, is outside the fixture's year window — 2011/2012/2019/2020 — so the test asserts the same invariant on Wisconsin state FY2012, where the fixture carries nonzero X01/X05/X08. Recorded in the test file as a comment.)
Cross-references
spend_typeclassification there first.summary_categoriesgap for prefixesX/Ybelongs tocensus_of_governments_finance_pipeline— see the crosswalk-coverage issue there.Severity: medium. Verdict: definitional.
Two findings from the pipeline crosswalk work published 2026-07-30 (
pipeline_commit e64a046), both of which change this issue's numbers.1. The crosswalk now carves out insurance trust for you
summary_categoriesgainedrevenue_subtype = "insurance_trust"for theYrevenue codes (Y01,Y02,Y04,Y11,Y12,Y51,Y52), pluscategory_type = "balance"for the holdings codes (pipeline#76/#78). So the general-vs-total split no longer needs a prefix rule at all.Measured on the regenerated fixture, Wisconsin state FY2012:
Filtering
revenue_subtype != 'insurance_trust'reproduces this issue'sgeneralfigure to the dollar, which is good evidence the subtype boundary is drawn where Census draws it.Note the balance codes are now separable too, which is what line 49's assertion needs:
X21/X30/X47arecategory_type = 'balance', andX11/X12are benefit payments. None of them can leak into a revenue concept once classification keys on the crosswalk instead of the letterX.2. This issue's expected
totalis now incompleteLine 41 asserts
total = 33,377,093,000, which isgeneral + X-retirement (2,038,800k)only. That was correct when written, because prefixYhad no crosswalk rows and so wasn't visible as revenue. It now is.A complete Census Total Revenue for WI FY2012 is:
So both the
totalexpectation and the delta on line 40 need updating when this is implemented.3. Caveat: today's default is not strictly Census General Revenue
Manual §4.3: "General revenue comprises all revenue except that classified as liquor store, utility, or insurance trust revenue."
Today's
flow_prefixes = c("T","A","U","B","C","D")admitsA90(liquor store) andA91–A94(utility current charges), so the current default is nearer General + Utility + Liquor Store than Census's General Revenue. It happens not to matter for the Wisconsin state example above — WI state carries$0forA90–A94in FY2012, which is why this issue's31,338,293,000baseline is unaffected — but it will matter for cities, where utility charges are often material.Worth deciding explicitly whether
generalmeans Census's General Revenue (excluding utility and liquor store) or "everything that isn't insurance trust". The crosswalk supports either: utility codes carry theWater/Electric/Gas/Transit Utilitiescategories, andA90isLiquor Stores.4. The naming caveat in the test header is now half-resolved
The owner ruled on 2026-07-30 (see uscogdata#11) that the default stays
general— insurance trust opt-in, not opt-out — on the grounds that it mirrors Census's published concepts and moves no existing caller's numbers. The argument name (revenue_concept) is still unruled.This also resolved a conflict with uscogdata#11, whose DoD item 4 required
Y01in the defaultcog_revenue()output. A default holdingY01but notX01matches no Census concept, so #11's proof moves off the default call instead.