Final-review findings F-1, F-2, F-6, F-8 (plus the F-9 @return reword,
which shares R/balances.R).
F-2: .validate_balance_inputs() checked 2 of cog_balances()' 7 arguments.
years = integer(0) leaked a raw DuckDB 'Parser Error ... AND year IN ()'
with the generated SQL echoed back; govid = character(0) and a non-character
category returned 0 rows with no error at all; recipe = c("a","b") threw
'the condition has length > 1' from inside .validate_recipe_id(). Replaced
with a call to the money verbs' own .validate_verb_inputs() (R/spending.R),
which validates the exact superset needed. Deleted the local copy rather
than extending it -- two validators is how they drift. Placed AFTER
.coerce_govid_input(), because .validate_verb_inputs() asserts
is.character(govid) and a data-frame govid is not unwrapped before that.
This is helper reuse of the same kind as .build_verb_sql()/.attach_per_capita();
the verb still does NOT route through .verb_spendrev().
F-1: falls out of F-2 for free -- the recipe/category mutual-exclusivity
guard lives inside .validate_verb_inputs(). Previously recipe silently
discarded category AND overwrote provenance$category with the recipe label,
so a caller asking for Fund Balances got X40/Z77 insurance-trust holdings
with no trace of the dropped filter.
F-6: cog_explain() rendered every provenance caveat block except
balance_caveats. Since .emit_balance_caveats() fires at most once per
session -- and is routinely consumed by a suppressMessages() call or an
unread knitr chunk -- cog_explain() is the only surface left for a caller
who deliberately audits the result. Added a 'Holdings caveats' section
guarded on !is.null(prov$balance_caveats). Also relabels the cosmetic
'Concept: NA' line on balance results as 'not applicable (holdings are a
stock, not a flow)'.
F-8: the coverage-window query has no govid and no year predicate -- its
answer depends only on the mounted corpus -- yet it scanned all of
balance_long on every call (35% of verb runtime on the fixture, and a
per-request throughput ceiling for cog-api#26). Memoised in
.uscogdata_env$balance_coverage_windows, invalidated by cog_close(), the
same pattern as .uscogdata_env$manifest.
77 lines
3.1 KiB
R
77 lines
3.1 KiB
R
% Generated by roxygen2: do not edit by hand
|
|
% Please edit documentation in R/balances.R
|
|
\name{cog_balances}
|
|
\alias{cog_balances}
|
|
\title{Cash and security holdings for one or more governments}
|
|
\usage{
|
|
cog_balances(
|
|
govid,
|
|
years,
|
|
category = NULL,
|
|
per_capita = FALSE,
|
|
adjust_to_year = NULL,
|
|
basis = c("harmonized", "raw"),
|
|
recipe = NULL
|
|
)
|
|
}
|
|
\arguments{
|
|
\item{govid}{Canonical govid(s): a character vector, or a data frame with a
|
|
`canonical_govid` column (e.g. from [cog_gov_search()]).}
|
|
|
|
\item{years}{Integer vector of fiscal years.}
|
|
|
|
\item{category}{Optional character vector of categories to keep. One of
|
|
`"Fund Balances"`, `"Insurance Trust Balances"`,
|
|
`"Retirement System Holdings"`. There is deliberately no `subtype`
|
|
argument: for holdings, `category` is a strict coarsening of
|
|
`balance_subtype` (unlike the money verbs, where the two axes cross), so
|
|
every combination would be either redundant or empty.
|
|
`category = "Fund Balances"` is exactly the `general` family
|
|
(`W01`/`W31`/`W61`). `balance_subtype` is returned, so a finer split is
|
|
one `dplyr::filter()` away.}
|
|
|
|
\item{per_capita}{Divide holdings by population. Note this is a **stock per
|
|
resident** (reserves per person), which is *not* comparable to
|
|
[cog_spending()]'s per-capita figures -- those are a flow per person.}
|
|
|
|
\item{adjust_to_year}{Deflate to this year's dollars (CPI-U).}
|
|
|
|
\item{basis}{Accepted for uniformity with the money verbs, but currently a
|
|
**no-op**: `harmonization_map` carries no balance-code rows, so harmonized
|
|
and raw space are identical for holdings. Reported in
|
|
`provenance$basis_note`.}
|
|
|
|
\item{recipe}{Optional harmonization recipe id (see [cog_recipes()]).
|
|
`"cash_securities_z77_wide"` and `"cash_securities_z78_wide"` bridge the
|
|
wide era to the modern one.}
|
|
}
|
|
\value{
|
|
Tibble with columns `year`, `canonical_govid`, `gov_name`,
|
|
`balance_subtype`, `category`, `amt_nominal`, `codes_included`,
|
|
`aggregate_fallback`, plus optional `amt_per_capita_nominal` and
|
|
`pop_source` (when `per_capita = TRUE`), optional `amt_real` (when
|
|
`adjust_to_year` is set), and optional `amt_per_capita_real` (only when
|
|
**both** `per_capita = TRUE` and `adjust_to_year` are set -- there is no
|
|
nominal per-capita column to deflate otherwise). Amounts are full US
|
|
dollars.
|
|
|
|
Carries a `provenance` attribute matching
|
|
`inst/schemas/provenance-v1.json`, whose `balance_caveats` block reports
|
|
`not_gaap`, `not_gaap_note`, `coverage_window` (measured year extents for
|
|
every balance subtype in the mounted corpus, not only the observed ones)
|
|
and `truncated` (the observed subtypes whose coverage falls short of the
|
|
requested years). `expenditure_concept`/`revenue_concept` are `NA` --
|
|
holdings are a stock, not a flow, so neither concept vocabulary applies.
|
|
}
|
|
\description{
|
|
Returns Census cash-and-security holdings (`category_type = "balance"`):
|
|
fund balances, retirement system holdings and insurance trust balances.
|
|
}
|
|
\section{Holdings are not GAAP fund balance}{
|
|
|
|
Census holdings are **gross** -- no liabilities are netted -- so a reserve
|
|
ratio built from them overstates what is actually available. They are not
|
|
comparable to a GAAP fund balance from an ACFR.
|
|
}
|
|
|