From d7dac60cd3b126bcd2eb4e24c75661b657d21dff Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Sun, 20 Sep 2026 16:03:15 -0400 Subject: [PATCH 1/2] Correct the uprating paragraph on the SPM methodology page The page said rent, child care, child support, the energy subsidy, real estate taxes and household assets and debts follow CPI-U, that workers' compensation follows employment income, and that every other dollar input follows CBO's adjusted gross income projection. Measured on main, 53 inputs follow CPI-U (utilities, phone and broadband, tuition, insurance, transportation and interest paid among them), 17 follow employment income, 18 follow CMS per-capita spending, employer-sponsored insurance premiums follow CBO employment income, alimony has its own IRS series and veterans' benefits follow the Social Security cost-of-living index. Rewrite the paragraph from the measured mapping and add a test that fails when an input follows a series the page does not link. Co-Authored-By: Claude Fable 5.1 --- ...-methodology-uprating-enumeration.fixed.md | 1 + docs-quarto/methodology/spm-poverty.qmd | 2 +- .../tests/core/test_uprating_series.py | 49 ++++++++++++++++++- 3 files changed, 50 insertions(+), 2 deletions(-) create mode 100644 changelog.d/fix-spm-methodology-uprating-enumeration.fixed.md diff --git a/changelog.d/fix-spm-methodology-uprating-enumeration.fixed.md b/changelog.d/fix-spm-methodology-uprating-enumeration.fixed.md new file mode 100644 index 00000000000..afe29b9c692 --- /dev/null +++ b/changelog.d/fix-spm-methodology-uprating-enumeration.fixed.md @@ -0,0 +1 @@ +Correct the SPM methodology page's account of which series each uprated input follows, and test that the page links every series an input follows. diff --git a/docs-quarto/methodology/spm-poverty.qmd b/docs-quarto/methodology/spm-poverty.qmd index 77c965c7c06..9bf7854c1a1 100644 --- a/docs-quarto/methodology/spm-poverty.qmd +++ b/docs-quarto/methodology/spm-poverty.qmd @@ -50,7 +50,7 @@ The [MOOP decomposition page](moop-decomposition.qmd) records the design and the Population results use the Microcosm US dataset. The current default is Build P: 57,240 Current Population Survey Annual Social and Economic Supplement households with 166,321 people, whose weights are fitted to 5,659 administrative and demographic targets (IRS Statistics of Income by state and by income, Census population estimates by age, sex and state, CMS Medicaid and Marketplace enrollment, USDA SNAP participation and benefits, SSA SSI, TANF, state tax collections and BEA national accounts). Poverty rates are never a target. That is a rule of the calibration, not an accident: a model whose weights were fitted to survey-based poverty rates could not be checked against them. -2025 values are the 2024 survey values carried forward by the model's uprating parameters: each uprated input grows by the ratio of its uprating series between the two years. Household weights grow with total population, so an input that follows a national total grows by that total divided by population ([`per_capita_uprating.py`](https://github.com/PolicyEngine/policyengine-us/blob/main/policyengine_us/tools/per_capita_uprating.py)); its weighted total then tracks the national total. The main income sources (employment, self-employment and partnership income, Social Security, pensions and retirement account distributions, capital gains, dividends, interest, rental and farm income, and unemployment compensation) follow [IRS Statistics of Income series](https://github.com/PolicyEngine/policyengine-us/tree/main/policyengine_us/parameters/calibration/gov/irs/soi). Each series holds IRS totals through its last recorded year and a CBO projection extends it from there, so the growth applied from 2024 to 2025 is CBO's, per capita. Non-premium medical spending and the survey-reported premiums that enter SPM resources follow [CMS's projection of per-capita out-of-pocket health spending](https://github.com/PolicyEngine/policyengine-us/blob/main/policyengine_us/parameters/calibration/gov/hhs/cms/moop_per_capita.yaml), which is already a per-person series. Rent, child care expenses, child support paid and received, the energy subsidy, real estate taxes, and household assets and debts follow [CPI-U](https://github.com/PolicyEngine/policyengine-us/blob/main/policyengine_us/parameters/gov/bls/cpi/cpi_u.yaml). Workers' compensation follows the employment income series. Every other dollar input follows [CBO's projection of total adjusted gross income](https://github.com/PolicyEngine/policyengine-us/blob/main/policyengine_us/parameters/calibration/gov/cbo/income_by_source.yaml), the default that [`default_uprating.py`](https://github.com/PolicyEngine/policyengine-us/blob/main/policyengine_us/tools/default_uprating.py) assigns, per capita like every national total. Household weights follow the model's [total population series](https://github.com/PolicyEngine/policyengine-us/blob/main/policyengine_us/parameters/calibration/gov/census/populations/total.yaml), which takes its values from CBO's demographic outlook; person and SPM unit weights read the household weight. Inputs without an uprating parameter (ages, take-up indicators, tenure, geography) carry over unchanged, so household composition is held at its 2024 state. The population is projected, not resampled. +2025 values are the 2024 survey values carried forward by the model's uprating parameters: each uprated input grows by the ratio of its uprating series between the two years. Household weights grow with total population, so an input that follows a national total grows by that total divided by population ([`per_capita_uprating.py`](https://github.com/PolicyEngine/policyengine-us/blob/main/policyengine_us/tools/per_capita_uprating.py)); its weighted total then tracks the national total. The main income sources (employment, self-employment and partnership income, Social Security, pensions and retirement account distributions, capital gains, dividends, interest, rental and farm income, alimony, and unemployment compensation) follow [IRS Statistics of Income series](https://github.com/PolicyEngine/policyengine-us/tree/main/policyengine_us/parameters/calibration/gov/irs/soi). Each series holds IRS totals through its last recorded year and a CBO projection extends it from there, so the growth applied from 2024 to 2025 is CBO's, per capita. Health costs follow [CMS's projection of per-capita out-of-pocket health spending](https://github.com/PolicyEngine/policyengine-us/blob/main/policyengine_us/parameters/calibration/gov/hhs/cms/moop_per_capita.yaml), which is already a per-person series: the non-premium medical spending and survey-reported premiums that enter SPM resources, the other premium and medical expense inputs, and health savings account payroll contributions. Expenses, assets and debts follow [CPI-U](https://github.com/PolicyEngine/policyengine-us/blob/main/policyengine_us/parameters/gov/bls/cpi/cpi_u.yaml): rent, child care and other care costs, child support paid and received, utilities, phone and broadband, tuition, homeowners insurance and association fees, transportation costs, interest paid on mortgages and other loans, real estate taxes, the energy subsidy, and household assets and debts. Pay-linked inputs follow the employment income series: hourly wages, tips, overtime premiums, military and government pay, the W-2 wages of qualified businesses, desired retirement contributions, workers' compensation and disability benefits. Employer-sponsored insurance premiums follow CBO's projection of employment income. Veterans' benefits follow the [Social Security cost-of-living index](https://github.com/PolicyEngine/policyengine-us/blob/main/policyengine_us/parameters/gov/ssa/uprating.yaml). Every other uprated dollar input follows [CBO's projection of total adjusted gross income](https://github.com/PolicyEngine/policyengine-us/blob/main/policyengine_us/parameters/calibration/gov/cbo/income_by_source.yaml), the default that [`default_uprating.py`](https://github.com/PolicyEngine/policyengine-us/blob/main/policyengine_us/tools/default_uprating.py) assigns, per capita like every national total. Household weights follow the model's [total population series](https://github.com/PolicyEngine/policyengine-us/blob/main/policyengine_us/parameters/calibration/gov/census/populations/total.yaml), which takes its values from CBO's demographic outlook; person and SPM unit weights read the household weight. Inputs without an uprating parameter (ages, take-up indicators, tenure, geography) carry over unchanged, so household composition is held at its 2024 state. The population is projected, not resampled. ## What the model does not do diff --git a/policyengine_us/tests/core/test_uprating_series.py b/policyengine_us/tests/core/test_uprating_series.py index 06595785de9..bc4630a242e 100644 --- a/policyengine_us/tests/core/test_uprating_series.py +++ b/policyengine_us/tests/core/test_uprating_series.py @@ -2,12 +2,14 @@ national series, the income source it is part of, prices for consumption expenses and debts, CMS per-capita spending for health costs.""" +from pathlib import Path + import pytest from policyengine_core.parameters.operations.get_parameter import get_parameter from policyengine_us.data.economic_assumptions import MICRODATA_UPRATING_OVERRIDES from policyengine_us.system import system -from policyengine_us.tools.per_capita_uprating import per_capita_path +from policyengine_us.tools.per_capita_uprating import DERIVED_FROM, per_capita_path EMPLOYMENT = per_capita_path("calibration.gov.irs.soi.employment_income") SELF_EMPLOYMENT = per_capita_path("calibration.gov.irs.soi.self_employment_income") @@ -138,3 +140,48 @@ def test_alimony_series_is_labelled_as_alimony(): def test_rent_override_matches_the_rent_input(): assert MICRODATA_UPRATING_OVERRIDES["rent"] == CPI_U assert system.variables["pre_subsidy_rent"].uprating == CPI_U + + +METHODOLOGY_PAGE = ( + Path(__file__).parents[3] / "docs-quarto" / "methodology" / "spm-poverty.qmd" +) +PARAMETERS_FOLDER = "policyengine_us/parameters/" + + +def _authored_series(uprating): + """The authored parameter behind an uprating path: a derived per-capita + series names the national total it divides.""" + parameter = get_parameter(system.parameters, uprating) + return parameter.metadata.get(DERIVED_FROM, uprating) + + +def _series_that_inputs_follow(): + return sorted( + { + _authored_series(variable.uprating) + for variable in system.variables.values() + if getattr(variable, "uprating", None) + } + ) + + +@pytest.mark.parametrize("series", _series_that_inputs_follow()) +def test_methodology_page_links_every_series_an_input_follows(series): + """The SPM methodology page names the series each family of inputs follows + and sends every other uprated input to the default. That stays true only + while the page links every series some input follows: the parameter's own + file, the file that holds it, or the folder that holds it.""" + if not METHODOLOGY_PAGE.exists(): + pytest.skip("The documentation is not part of an installed package.") + page = METHODOLOGY_PAGE.read_text() + path = series.replace(".", "/") + holder = path.rpartition("/")[0] + links = ( + f"{PARAMETERS_FOLDER}{path}.yaml", + f"{PARAMETERS_FOLDER}{holder}.yaml", + f"{PARAMETERS_FOLDER}{holder})", + ) + assert any(link in page for link in links), ( + f"{METHODOLOGY_PAGE.name} does not link {series}, which uprates at " + "least one input. Say on the page which inputs follow it." + ) From 29a56c615dd91271a63838774707f3c29fd247ed Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Sat, 26 Sep 2026 11:46:17 -0400 Subject: [PATCH 2/2] Name exactly which inputs follow each uprating series on the SPM methodology page Co-Authored-By: Claude Opus 5.5 --- docs-quarto/methodology/spm-poverty.qmd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs-quarto/methodology/spm-poverty.qmd b/docs-quarto/methodology/spm-poverty.qmd index 9bf7854c1a1..40d24f8a664 100644 --- a/docs-quarto/methodology/spm-poverty.qmd +++ b/docs-quarto/methodology/spm-poverty.qmd @@ -50,7 +50,7 @@ The [MOOP decomposition page](moop-decomposition.qmd) records the design and the Population results use the Microcosm US dataset. The current default is Build P: 57,240 Current Population Survey Annual Social and Economic Supplement households with 166,321 people, whose weights are fitted to 5,659 administrative and demographic targets (IRS Statistics of Income by state and by income, Census population estimates by age, sex and state, CMS Medicaid and Marketplace enrollment, USDA SNAP participation and benefits, SSA SSI, TANF, state tax collections and BEA national accounts). Poverty rates are never a target. That is a rule of the calibration, not an accident: a model whose weights were fitted to survey-based poverty rates could not be checked against them. -2025 values are the 2024 survey values carried forward by the model's uprating parameters: each uprated input grows by the ratio of its uprating series between the two years. Household weights grow with total population, so an input that follows a national total grows by that total divided by population ([`per_capita_uprating.py`](https://github.com/PolicyEngine/policyengine-us/blob/main/policyengine_us/tools/per_capita_uprating.py)); its weighted total then tracks the national total. The main income sources (employment, self-employment and partnership income, Social Security, pensions and retirement account distributions, capital gains, dividends, interest, rental and farm income, alimony, and unemployment compensation) follow [IRS Statistics of Income series](https://github.com/PolicyEngine/policyengine-us/tree/main/policyengine_us/parameters/calibration/gov/irs/soi). Each series holds IRS totals through its last recorded year and a CBO projection extends it from there, so the growth applied from 2024 to 2025 is CBO's, per capita. Health costs follow [CMS's projection of per-capita out-of-pocket health spending](https://github.com/PolicyEngine/policyengine-us/blob/main/policyengine_us/parameters/calibration/gov/hhs/cms/moop_per_capita.yaml), which is already a per-person series: the non-premium medical spending and survey-reported premiums that enter SPM resources, the other premium and medical expense inputs, and health savings account payroll contributions. Expenses, assets and debts follow [CPI-U](https://github.com/PolicyEngine/policyengine-us/blob/main/policyengine_us/parameters/gov/bls/cpi/cpi_u.yaml): rent, child care and other care costs, child support paid and received, utilities, phone and broadband, tuition, homeowners insurance and association fees, transportation costs, interest paid on mortgages and other loans, real estate taxes, the energy subsidy, and household assets and debts. Pay-linked inputs follow the employment income series: hourly wages, tips, overtime premiums, military and government pay, the W-2 wages of qualified businesses, desired retirement contributions, workers' compensation and disability benefits. Employer-sponsored insurance premiums follow CBO's projection of employment income. Veterans' benefits follow the [Social Security cost-of-living index](https://github.com/PolicyEngine/policyengine-us/blob/main/policyengine_us/parameters/gov/ssa/uprating.yaml). Every other uprated dollar input follows [CBO's projection of total adjusted gross income](https://github.com/PolicyEngine/policyengine-us/blob/main/policyengine_us/parameters/calibration/gov/cbo/income_by_source.yaml), the default that [`default_uprating.py`](https://github.com/PolicyEngine/policyengine-us/blob/main/policyengine_us/tools/default_uprating.py) assigns, per capita like every national total. Household weights follow the model's [total population series](https://github.com/PolicyEngine/policyengine-us/blob/main/policyengine_us/parameters/calibration/gov/census/populations/total.yaml), which takes its values from CBO's demographic outlook; person and SPM unit weights read the household weight. Inputs without an uprating parameter (ages, take-up indicators, tenure, geography) carry over unchanged, so household composition is held at its 2024 state. The population is projected, not resampled. +2025 values are the 2024 survey values carried forward by the model's uprating parameters: each uprated input grows by the ratio of its uprating series between the two years. Household weights grow with total population, so an input that follows a national total grows by that total divided by population ([`per_capita_uprating.py`](https://github.com/PolicyEngine/policyengine-us/blob/main/policyengine_us/tools/per_capita_uprating.py)); its weighted total then tracks the national total. The main income sources (employment, self-employment and partnership income, Social Security, pensions and retirement account distributions, capital gains, dividends, interest, rental and farm income, alimony received and paid, and unemployment compensation) follow [IRS Statistics of Income series](https://github.com/PolicyEngine/policyengine-us/tree/main/policyengine_us/parameters/calibration/gov/irs/soi). Each series holds IRS totals through its last recorded year and a CBO projection extends it from there, so the growth applied from 2024 to 2025 is CBO's, per capita. These health inputs follow [CMS's projection of per-capita out-of-pocket health spending](https://github.com/PolicyEngine/policyengine-us/blob/main/policyengine_us/parameters/calibration/gov/hhs/cms/moop_per_capita.yaml), which is already a per-person series: the other medical expenses, over-the-counter health expenses and other health insurance premiums that enter SPM resources; physician services, inpatient, outpatient, emergency room, urgent care, ambulance, imaging, lab and prescription expenses; health insurance premiums in total, pre-tax, long-term and excluding Medicare Part B, and reported Medicare Part B premiums; and health savings account payroll contributions. These expenses, assets and debts follow [CPI-U](https://github.com/PolicyEngine/policyengine-us/blob/main/policyengine_us/parameters/gov/bls/cpi/cpi_u.yaml): rent, child care and other care costs, child support paid and received, utilities, phone and broadband, tuition, homeowners insurance and association fees, transportation costs, real estate taxes and the energy subsidy; the person-level home mortgage interest input, student loan interest, investment interest expense and vehicle loan interest; bank account, stock and bond assets and the value of the primary residence; the value, equity and debt of business assets, rental property and other real estate; and vehicle equity and debt, the auto loan balance and net worth. These pay and wage-replacement inputs follow the IRS employment income series: hourly wages, tips, overtime premiums, military and government pay, the W-2 wages of qualified businesses, desired 401(k), 403(b) and IRA contributions, workers' compensation and disability benefits. Desired self-employed pension contributions follow the IRS self-employment income series. Employer-sponsored insurance premiums follow CBO's projection of employment income. Veterans' benefits follow the [Social Security cost-of-living index](https://github.com/PolicyEngine/policyengine-us/blob/main/policyengine_us/parameters/gov/ssa/uprating.yaml). Every other uprated dollar input follows [CBO's projection of total adjusted gross income](https://github.com/PolicyEngine/policyengine-us/blob/main/policyengine_us/parameters/calibration/gov/cbo/income_by_source.yaml), the default that [`default_uprating.py`](https://github.com/PolicyEngine/policyengine-us/blob/main/policyengine_us/tools/default_uprating.py) assigns, per capita like every national total. Inputs on the default include tax units' first and second home mortgage interest and balances, home equity, personal property, SPM unit assets, mortgage payments, charitable donations, casualty losses, educator expenses, tax preparation fees, energy efficiency and clean energy property expenditures, state unemployment insurance wage and earnings inputs, employer payroll totals and local earnings and wage tax inputs. Household weights follow the model's [total population series](https://github.com/PolicyEngine/policyengine-us/blob/main/policyengine_us/parameters/calibration/gov/census/populations/total.yaml), which takes its values from CBO's demographic outlook; person and SPM unit weights read the household weight. Inputs without an uprating parameter (ages, take-up indicators, tenure, geography) carry over unchanged, so household composition is held at its 2024 state. The population is projected, not resampled. ## What the model does not do