Expose cash and security holdings (category_type = balance), and keep them out of the money verbs #25
Closed
opened 2026-07-30 14:48:49 -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.
No labels
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#25
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.
census_of_governments_finance_pipeline#76(PR #77) adds a thirdcategory_typetosummary_categories.csv—balance— covering the 14cash-and-security holding codes, with a
balance_subtypecolumn. The readerhas no way to reach them and no guard against them leaking into money verbs.
Blocked on: the corpus rebuild + republish that ships pipeline PR #77.
Nothing here is testable until
summary_categories.parquetcarries the newcolumn.
Two requirements
1. Neither money verb may admit a
balancerowcog_spending()andcog_revenue()must never return one. These are stocks— a balance at a point in time — while the money verbs return flows over a
fiscal year. Summing a stock with a flow is meaningless, and worse, a
balancerow silently included in a spending total looks plausible rather thanobviously wrong.
This should be an explicit filter on
category_type, not an incidentalconsequence of prefix matching. The pipeline guards its own artifacts with a
single
.drop_balance()predicate for exactly this reason; the reader wantsthe same shape.
Note this interacts with
#11and#12: whatever classifies codes intoexpenditure/revenue concepts must treat
balanceas a third outcome ratherthan forcing every code into one of two buckets.
2. A way to query holdings
Design TBD. The two obvious shapes:
cog_balances(), parallel tocog_spending()/cog_revenue();A verb is probably right given the return semantics genuinely differ (no
amt_per_capitainterpretation as "spending per person"; year-over-year changeis portfolio movement, not budget growth), but that is an owner call.
Whatever the shape,
balance_subtype == "general"(W01/W31/W61) must bereachable in one filter — that is the family users mean by "fund balance".
Caveats the reader must surface, not bury
These are in
docs/data_dictionary.md§ Cash and security holdings and shouldreach the user, because each one silently invalidates an obvious analysis:
liabilities netted. A reserve ratio built from them overstates what is
actually available.
Wis FY2012–2021 only — ten years, stopping two short of the corpus.A long fund-balance-share-of-revenue series is not available.
Xfamily ends at FY2016, when Census moved employee retirement toa separate survey.
X40/X41change valuation basis mid-series at FY2002 (book → market)while keeping the same code through FY2011 — catalogued as
SB195/SB196.Undetectable from the series alone.
The subtype map
balance_subtypegeneralW01,W31,W61employee_retirementX21,X30,X42,X44,X47,Z77,Z78unemployment_trustY07,Y08workers_comp_trustY21other_insurance_trustY61Downstream: the API surface follows this (
cog-api).Requirement 1 is shipped and asserted. Requirement 2 is untouched and still needs an owner design call, so this stays open — re-scoped to the query surface only.
Requirement 1 — no
balancerow in a money verb: DONEDelivered by uscogdata#11 (merged,
93300ae) and extended by #12 (4b23dbd). It is an explicit consequence ofcategory_type, exactly as this issue asked, not an incidental effect of prefix matching — the flow views now select on crosswalk membership, so abalancecode cannot reach either verb by construction:This issue's note that "whatever classifies codes into expenditure/revenue concepts must treat
balanceas a third outcome rather than forcing every code into one of two buckets" is precisely what shipped:category_typeis the classifier, andbalanceis one of its three values.Guarded at both levels so a regression fails loudly:
test-views.R) —spending_longandrevenue_longeach assert zero rows whoseitem_codeis acategory_type = 'balance'member.test-expenditure-concepts.R) — asserted on Wisconsin FY2019, a government-year that genuinely carriesY07/Y08/Y21balance rows, against bothexpenditure_concept = "total"and (as of #12)revenue_concept = "total", the two widest concepts and therefore the ones most able to over-admit.The
Yfamily is the case that makes this non-trivial and it is covered: one letter spanning revenue (Y01), expenditure (Y05) and balance (Y07). #12 addedXas a second such letter —X01revenue,X11expenditure,X21balance — so there are now two independent proofs that prefix logic could not have delivered this.Requirement 2 — a way to query holdings: NOT STARTED
Still an owner call, and still the whole remaining scope of this issue. The design question from the original post is unchanged:
cog_balances()verb, parallel to the money verbs; orMy read is that the issue's own instinct is right — a separate verb. The return semantics genuinely differ:
amt_per_capitadoes not mean "holdings per person" in any useful sense, year-over-year change is portfolio movement rather than budget growth, and the flow verbs' wholeexpenditure_concept/revenue_conceptvocabulary is meaningless for a stock. Overloading a money verb would put a stock behind arguments that all assume a flow.Two things worth deciding at the same time:
X/Zholdings stop at FY2016 (series breaksSB197-SB202, shipped with #12) when employee retirement moved to the Annual Survey of Public Pensions. Any holdings verb needs to surface that seam rather than let a series appear to collapse.X40/X41switch from book value to market value at FY2002 inside a surviving code (SB195/SB196), so a holdings series is continuous in identity but not in basis.cog-api#26 is blocked on this half.