Repository navigation
Load CBO's February 2026 projections through 2036 into the upraters - #10227
Conversation
|
Local check status:
|
69b39ee to
53c4fb3
Compare
53c4fb3 to
b08acc7
Compare
SSA and SNAP uprating and the national average wage index grow from their latest actuals at CBO's February 2026 rates. The payroll cap applies 42 U.S.C. 430(b) to that wage index, CPI-W extends to 2036Q4 at its existing ratio, and the HHS index grows from its 2026 value. CPI-U and chained CPI-U keep CBO's 2035 projection point instead of extrapolating over it, and IRS uprating reads it for 2036. Every refreshed series extrapolates only from 2037. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
b08acc7 to
4510721
Compare
Oregon ERDC's 2027 initial income limit is 200% of the projected 2027 poverty guideline. Growing HHS uprating at CBO's 2027 rate moves the boundary from 3,692 to 3,699, so the strict-limit case now uses 3,699. The FY2028 SNAP maximum allotment uprates the published FY2027 value. Growing from June 2026 CPI-U at CBO's 2027Q2 rate gives 342.578, not CBO's older 335.5 level, so the four-person allotment is 1,049.42. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The reform's 2027 standard deduction equals the projected poverty guideline for the household's size. HHS uprating now grows 2027 at CBO's rate (336.766 / 328.4), so the one-, two- and four-person values are 16,367, 22,191 and 33,841. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
PavelMakarchuk
left a comment
There was a problem hiding this comment.
Program Review
PR #10227, "Load CBO's February 2026 projections through 2036 into the upraters" (DTrim99). Round 1, full review.
IDs: C = critical, SA = should address, G = suggestion.
Paths: U = policyengine_us/parameters/uprating_extensions.py, T = policyengine_us/tests/policy/baseline/parameters/test_uprating_extensions.py. Parameter paths such as gov/ssa/uprating.yaml are under policyengine_us/parameters/. Line numbers refer to the reviewed head. PDF links use the file page number (file page = printed page + 8 in the CBO report).
Source Documents
- Workbook: CBO, Economic Projections, February 2026: sheet "1. Quarterly", row 53 (CPI-U, 2023Q1-2036Q4); sheet "2. Calendar Year", rows 53 (CPI-U) and 57 (chained CPI-U), 2023-2036. No sheet has a CPI-W series.
- Workbook: CBO, Tax Parameters, February 2026: sheet "1. Tax Parameters", row 155 (maximum taxable earnings, 2022-2036) and rows 152-153 (CPI-U and chained CPI-U, 12 months ending August).
- Workbook: CBO, Economic Projections, January 2025, the original release and CBO's April 30, 2025 update (calendar 2026 CPI-U = 328.446), and the February 2024 workbook for comparison (calendar 2026 CPI-U = 327.896).
- CSV: US-CBO/cbo-data at 284a956:
quarterly_2026-02.csv,calendar_2026-02.csv,annual_cy_2026-02.csvandcalendar_2025-01.csv. They equal the workbook rows: 0 differences over 56 quarterly, 14 calendar and 15 tax-parameter points. - PDF: CBO, The Budget and Economic Outlook: 2026 to 2036 (173 pages, corrected March 24, 2026; the February 9 original was also read): file pages 35 (Table 2-1), 74 (projected COLAs), 120 (Figure 5-2, CPI-W) and 163 (Table D-1).
- Law: 42 U.S.C. 430(b), 42 U.S.C. 415(i), 42 U.S.C. 9902(2), 7 U.S.C. 2012(u)(3)(C) and (u)(4), Pub. L. 119-21 sec. 10101(a), 26 U.S.C. 1(f), 20 CFR 404.1048(b)(2), 7 CFR 273.10(e)(4)(ii), 7 U.S.C. 2014(e)(1)(A).
- Agency pages: SSA AWI series, contribution and benefit base, CBB method, 2027 COLA fact sheet, CPI-W monthly, COLA series; BLS CWUR0000SA0, CUUR0000SA0, CUSR0000SA0 and SUUR0000SA0, monthly through September 2026; HHS poverty guideline notices FR 2022-01166, 2023-00885, 2024-00796, 2025-01377 and 2026-00755, and the ASPE guidelines page; USDA FNS Food Plans monthly cost reports, the FY2026 and FY2027 SNAP COLA memos and the June 2021-September 2026 TFP cost file.
- Access: cbo.gov and ssa.gov return 403 to scripts. Their files were read from Wayback captures with the same digest as the live files.
- Year: target 2026-2036. The PR changes projected values from 2026 (NAWI) and 2027 (HHS, SNAP) through 2036, and the year in which each extrapolation starts.
- Scope: Full. 12 files, 230 insertions and 114 deletions against merge base
f45d36a7d1. - Reviewed head SHA: 493ec45
- Mode: full
Branch Status
- The branch is 3 commits ahead and 47 behind
main(237da945eb), and it is MERGEABLE. The staleness did not affect any finding. - Merge condition: the PR's own hold. Do not merge until spm-calculator 1.1.0 (PolicyEngine/spm-calculator#51) is released, per PolicyEngine/policyengine-api#3926. On 2026-10-23, PyPI has spm-calculator 1.0.1. This is a merge condition, not a finding about the code.
What is correct
All 198 changed values recompute from the cited CBO, SSA and BLS data with 0 mismatches, and every comment formula in the changed YAML gives its value. The anchors are right: SSA 2027 = 328.746 is the 2026Q3 CPI-W mean (327.104, 328.481, 330.654) and gives the published 3.6% COLA; SNAP October 2026 = 333.952 is June 2026 CPI-U; NAWI 2025 = 72,800.33 is SSA's published value; the 2026 and 2027 caps are SSA's 184,500 and 192,300. The anchor-and-grow method is sound. The NAWI back-out divides by CBO's own 2027 base (191,100), which keeps CBO's growth on one vintage. The 2028-2036 caps follow 42 U.S.C. 430(b) exactly, and no product is on a $150 tie. The 2027 wage-indexed amounts reproduce the SSA fact sheet (quarter of coverage $1,970, earnings test $25,560, SGA $1,770). The SSA CPI-U proxy agrees with CBO's own COLA path: CBO projects COLAs of 2.3% a year for 2029-2036 (#page=74), and the PR's implied COLAs average 2.27%. NAWI ends in 2034, the year behind CBO's last base (2036), and nothing reads NAWI 2035 as a CBO point. The CPI-U and chained CPI-U fix is right: CBO's 2035 points 407.3 and 219.2 now survive the extension (before: 407.40 and 219.08). The PR-body tables reproduce: 98 checkable rows of the nine 2027-2037 tables, the IRS 2027 row and all nine rows of the 2036 table. The three moved YAML tests are right: ERDC Case 2 is still exactly at the strict limit (ceil(2 x 22,191.28 / 12) = 3,699 and the rule is <), the SNAP FY2028 allotment is 1,023 x 342.578 / 333.952 = 1,049.42, and the six AB 2591 cases are within their $1 margin. No partner file is edited, all 623 partner tests pass in a local read-only run, and CI passes 27 of 27. The changelog fragment is top-level, typed changed and named after the branch. The PR body has the axiom line.
Critical (Must Fix)
C1. The SNAP uprater cites the wrong paragraph of 7 U.S.C. 2012(u).
- Where:
gov/usda/snap/uprating.yaml:29-30(title: 7 U.S. Code § 2012(u)(4),href: ...2012#u_4). - What is wrong: Pub. L. 119-21 sec. 10101(a) (July 4, 2025) rewrote subsection (u). The October 1 adjustment "to reflect changes in the Consumer Price Index for All Urban Consumers ... for the most recent 12-month period ending in June" is now (u)(3)(C). Paragraph (u)(4) is now "Re-evaluation of market baskets". The enrolled law has the same structure (#page=11). The citation was right when #3976 added it in February 2024, because the former (u)(4) held the June adjustment. It became wrong in July 2025.
- Why this PR: the two lines are unchanged context, but the PR rewrites the reference list of this block (it replaces the CBO 59710 entry). The citation is the only legal basis for the 10 values that the PR changes (October 2027 to October 2036), and the PR's method (June 2026 actual x CBO Q2 growth) uses the (u)(3)(C) text. An incorrect section citation is critical.
mainstill has it, and no issue or PR tracks it. The fix changes metadata only. No value or test moves. - Fix: replace lines 29-30:
- title: 7 U.S. Code § 2012(u)(3)(C)
href: https://www.law.cornell.edu/uscode/text/7/2012#u_3_COptional, for the 2020-2024 actuals (former rule) and the link to the maximum allotments:
- title: 7 U.S. Code § 2012(u)(4) (2023 edition, before Pub. L. 119-21)
href: https://www.govinfo.gov/content/pkg/USCODE-2023-title7/html/USCODE-2023-title7-chap51-sec2012.htm
- title: 7 CFR 273.10(e)(4)(ii)
href: https://www.ecfr.gov/current/title-7/part-273/section-273.10#p-273.10(e)(4)(ii)Should Address
SA1. The payroll cap extension after 2036 does not use the 42 U.S.C. 430(b) formula.
- Where:
U:774-810(extend_social_security_payroll_cap, docstring atU:782-784), called atU:994-998with the new start year. The test isT:313-318. The PR's own 430(b) loop isT:459-462. - What is wrong: the function chains the rounded prior-year cap: round300(cap(Y-1) x NAWI(Y-2) / NAWI(Y-3)). 42 U.S.C. 430(b) uses a fixed base: the larger of the base in effect and $60,600 x NAWI(Y-2) / NAWI(1992), rounded to the nearest $300 (a multiple of $150 rounds up). SSA's method page states the same fixed-base formula. The docstring says that the function "follows the statutory formula in 20 CFR 404.1048". 20 CFR 404.1048(b)(2)(i) still has the chained wording, but its last amendment is from 1992. Pub. L. 103-296 sec. 321(g)(1) replaced that formula for bases after 1994, so the statute controls.
- Evidence: a probe shows that the fixed-base formula reproduces all 30 actual bases from 1995 to 2027. The chained wording reproduces only 20 of 30 (it misses by $300 in 1997-2000, 2009, 2013, 2014, 2017, 2018 and 2022). For 2037-2100 the head differs from 430(b) in 44 of 64 years: +$300 in 16 years from 2040 to 2061 (2040: 295,800 against 295,500) and -$300 to -$1,500 in all 28 years from 2073 to 2100 (2100: 1,993,800 against 1,995,300). The same values feed
gov.ssa.social_security.wage_base. The PR now states and tests 430(b) for 2028-2036 (gov/irs/payroll/social_security/cap.yaml:64-76,T:459-462), so one parameter follows two methods with a seam at 2037, and one test file asserts two formulas for the same quantity. The function predates the PR (#7912). The PR moves its start year and edits theT:313year list that pins the chained values. No issue tracks it. - Severity: the indexing structure is right and the rounding enters at the wrong place, so this is should-address, not critical. The largest gap is 0.10%. No test outcome and no partner pin moves.
- Fix: a mutation test on a copy with this fix passes
test_uprating_extensions.py,tests/policy/contrib/ssa/test_trustees_core_thresholds.pyandtests/core/test_per_capita_uprating.py(99 passed) and the four YAML files with periods of 2036 or later. Then 0 of 64 years differ from 430(b). ReplaceU:774-810:
def extend_social_security_payroll_cap(
parameters: ParameterNode,
last_projected_year: int,
end_year: int,
) -> None:
"""
Extend the Social Security contribution and benefit base through `end_year`.
Follows 42 U.S.C. 430(b) on the projected national average wage index
(NAWI): the base for year Y is the larger of the base in effect for Y - 1
and the 1994 base ($60,600) times NAWI(Y - 2) / NAWI(1992), rounded to the
nearest $300 (a multiple of $150 rounds up). 20 CFR 404.1048(b)(2)(i)
still states the pre-1995 chained formula, which Pub. L. 103-296,
sec. 321(g)(1), replaced for bases after 1994.
"""
cap = parameters.gov.irs.payroll.social_security.cap
nawi = parameters.gov.ssa.nawi
base_1994 = cap("1994-01-01")
nawi_1992 = nawi("1992-01-01")
for year in range(last_projected_year + 1, end_year + 1):
current_cap = cap(f"{year - 1}-01-01")
proposed_cap = round_social_security_payroll_cap(
base_1994 * nawi(f"{year - 2}-01-01") / nawi_1992
)
cap.update(
period=f"year:{year}-01-01:1",
value=max(current_cap, proposed_cap),
)
final_value = cap(f"{end_year}-01-01")
cap.update(start=instant(f"{end_year}-01-01"), value=final_value)Replace T:313-318. The list adds 2073, the first year in which the old chain falls below the statute:
# 42 U.S.C. 430(b): fixed 1994 base, never below the prior year's base.
for year in [2037, 2040, 2050, 2073, 2100]:
expected_cap = max(
payroll_cap(f"{year - 1}-01-01"),
round_social_security_payroll_cap(
payroll_cap("1994-01-01")
* nawi(f"{year - 2}-01-01")
/ nawi("1992-01-01")
),
)
assert payroll_cap(f"{year}-01-01") == expected_capThe fix also covers the other caller, policyengine_us/reforms/ssa/trustees_2025.py:198-202. If you prefer to keep the function body out of this PR, correct the docstring here and open the follow-up issue "Extend the Social Security payroll cap with the 42 U.S.C. 430(b) fixed-base formula".
SA2. The new tests do not pin the CBO points that set the 2037-2100 path.
- Where:
T:430-474(test_upraters_follow_cbo_february_2026_growth_through_2036) andT:477-502(test_upraters_extrapolate_only_after_cbo_projections).extend_parameter_values(U:742-751) grows every year after the last CBO year L at p(L) / p(L-1). - Part 1, p(L-1) is not pinned. A mutation test multiplied one second-to-last point at a time by 1.01. All 40 tests pass for SSA 2035 (
gov/ssa/uprating.yaml:19, 394.385 to 398.329), SNAP October 2035 (gov/usda/snap/uprating.yaml:21), HHS 2035 (gov/hhs/uprating.yaml:20), CPI-W 2035-02-01 and 2036-02-01 (gov/bls/cpi/cpi_w.yaml:1404, 1408) and CPI-U 2034-02-01 (gov/bls/cpi/cpi_u.yaml:1374, an older value that the new CPI-U end year makes the growth base). For SSA the long-run growth falls from 2.257% to 1.245% a year, and the 2100 index falls 47.1% (1,682.75 to 890.10). The CPI-W 2036-02-01 mutant raises CPI-W 2100 by 91%.test_uprating_growth_rates_are_reasonableaccepts every mutant, because it allows any growth from 0.5% to 5%. NAWI 2033 is protected: the cap loop atT:459-462catches it. - Part 2, the parametrized test misses an extension that starts one year early. If
last_projected_yearis L-1, the extension overwrites p(L) with p(L-1) x g, so p(L) / p(L-1) equals every later growth. A mutation test confirms that all 9 such mutants (one constant at a time) pass the parametrized test. This is the overwrite that the PR fixes for CPI-U and chained CPI-U. The 40-test suite catches each one only through one endpoint assertion in the other test. For SSA, SNAP and HHS that margin is 2.89x, 2.29x and 6.25x theabs=5e-4tolerance, and it exists only because CBO's last two growth rates differ in the sixth digit. With a later CBO vintage whose final growth rates are flatter, these regressions pass silently. The parametrized test does catch all 8 "starts one year late" mutants. - Also: the IRS 2036 assertion (
T:472-474) compares withget_irs_cpi(parameters, 2035), the same call as the code atU:954, so it pins no number. A mutation of chained CPI-U 2034-02-01 moves IRS 2036 by +0.48%, and that line still passes. IRS 2036 is 217.05 = (6 x 214.9 + 6 x 219.2) / 12 (see G3 for the window). - Fix: append after
T:502. The expected values come only from CBO February 2026 data at 284a956 and from the anchors thatTalready pins. None reads a parameter. At the head the block passes 16 of 16, and the whole file passes 56 of 56. The block kills every mutant above except the cap "starts early" mutant, whichT:463already catches.ruff formatmakes no change.
# CBO February 2026 (US-CBO/cbo-data at 284a956; quarterly_2026-02.csv and
# calendar_2026-02.csv cpiu / chained_cpiu, annual_cy_2026-02.csv
# tp_ss_max_earnings): the last two CBO points of each series.
# extend_parameter_values grows every year after the last point at the ratio
# of these two points, so both must be CBO's values.
CBO_2026_02_SEAM_QUARTERLY_CPI_U = {
"2026Q2": 330.708,
"2026Q3": 332.976,
"2034Q3": 399.460,
"2035Q1": 403.943,
"2035Q2": 406.203,
"2035Q3": 408.476,
"2036Q1": 413.061,
"2036Q2": 415.373,
}
CBO_2026_02_SEAM_CALENDAR_CPI_U = {
2026: 331.807,
2034: 398.355,
2035: 407.346,
2036: 416.542,
}
CBO_2026_02_SEAM_CALENDAR_C_CPI_U = {2033: 210.759, 2034: 214.912, 2035: 219.152}
CBO_2026_02_SEAM_CBB = {2027: 191_100, 2035: 250_500, 2036: 258_600}
_Q = CBO_2026_02_SEAM_QUARTERLY_CPI_U
_CY = CBO_2026_02_SEAM_CALENDAR_CPI_U
_CC = CBO_2026_02_SEAM_CALENDAR_C_CPI_U
_CBB = CBO_2026_02_SEAM_CBB
@pytest.mark.parametrize(
"path,date,expected,decimals",
[
# SSA: 2027 anchor 328.746 x CBO CPI-U Q3(Y-1) / 2026Q3.
("gov.ssa.uprating", "2035-01-01", 328.746 * _Q["2034Q3"] / _Q["2026Q3"], 3),
("gov.ssa.uprating", "2036-01-01", 328.746 * _Q["2035Q3"] / _Q["2026Q3"], 3),
# SNAP: June 2026 CPI-U 333.952 x CBO CPI-U Q2(Y) / 2026Q2.
(
"gov.usda.snap.uprating",
"2035-10-01",
333.952 * _Q["2035Q2"] / _Q["2026Q2"],
3,
),
(
"gov.usda.snap.uprating",
"2036-10-01",
333.952 * _Q["2036Q2"] / _Q["2026Q2"],
3,
),
# HHS: 2026 value 328.4 x CBO calendar CPI-U(Y) / calendar 2026.
("gov.hhs.uprating", "2035-01-01", 328.4 * _CY[2035] / _CY[2026], 3),
("gov.hhs.uprating", "2036-01-01", 328.4 * _CY[2036] / _CY[2026], 3),
# CPI-W February points: CBO CPI-U Q1 x June 2026 CPI-W / CPI-U.
(
"gov.bls.cpi.cpi_w",
"2035-02-01",
_Q["2035Q1"] * 327.075 / 333.952,
3,
),
(
"gov.bls.cpi.cpi_w",
"2036-02-01",
_Q["2036Q1"] * 327.075 / 333.952,
3,
),
# NAWI: SSA's 2025 AWI 72,800.33 x CBO CBB(Y+2) / CBB 2027.
("gov.ssa.nawi", "2033-01-01", 72_800.33 * _CBB[2035] / _CBB[2027], 2),
("gov.ssa.nawi", "2034-01-01", 72_800.33 * _CBB[2036] / _CBB[2027], 2),
# CPI-U and chained CPI-U: CBO calendar year Y at the Y-02-01 instant,
# one decimal. Chained 2033 feeds the IRS 2035 window.
("gov.bls.cpi.cpi_u", "2034-02-01", _CY[2034], 1),
("gov.bls.cpi.cpi_u", "2035-02-01", _CY[2035], 1),
("gov.bls.cpi.c_cpi_u", "2033-02-01", _CC[2033], 1),
("gov.bls.cpi.c_cpi_u", "2034-02-01", _CC[2034], 1),
("gov.bls.cpi.c_cpi_u", "2035-02-01", _CC[2035], 1),
],
)
def test_upraters_encode_the_cbo_points_behind_long_run_growth(
path, date, expected, decimals
):
"""The last two CBO points of each series set its 2037-2100 growth."""
assert PARAMETERS.get_child(path)(date) == round(expected, decimals)
def test_irs_uprating_averages_cbo_chained_cpi_u_points():
"""IRS(Y) = get_irs_cpi(Y - 1): chained CPI-U from August Y-2 to July Y-1.
Six months read the February Y-2 point and six read February Y-1.
"""
irs = PARAMETERS.gov.irs.uprating
c_cpi_u = {year: round(value, 1) for year, value in _CC.items()}
assert irs("2035-01-01") == pytest.approx(
(6 * c_cpi_u[2033] + 6 * c_cpi_u[2034]) / 12, rel=1e-12
)
assert irs("2036-01-01") == pytest.approx(
(6 * c_cpi_u[2034] + 6 * c_cpi_u[2035]) / 12, rel=1e-12
)If you also apply G1 option A, move the CPI-U and chained CPI-U rows one year later (CPI-U 2035 and 2036; chained 2034, 2035 and 2036, with _CY[2036] and a chained 2036 entry of 223.479). If #9105 changes the IRS window, the IRS test changes to a 5 and 7 month split.
SA3. The reference for the HHS 2026 anchor names the wrong CBO report.
- Where:
gov/hhs/uprating.yaml:34-36. The PR changed the comment on line 35. The title and the href are older (#6343). - What is wrong: 328.4 is CBO's January 2025 projection of calendar 2026 CPI-U (328.446, workbook for "The Budget and Economic Outlook: 2025 to 2035"). The title names the February 2024 report ("2024 to 2034"), whose calendar 2026 value is 327.896. The href
https://www.cbo.gov/data/budget-economic-data#4is an index of more than 20 vintages, not the file. "Row 51" is right only for the original January 2025 release. CBO's April 30, 2025 update inserted medical price rows, and CPI-U is now row 53 of "2. Calendar Year" (value unchanged). The PR uses 328.4 as the anchor of all 10 changed HHS values (gov/hhs/uprating.yaml:12-21). - Severity: the value is right, and the comment leads a careful reader to the right file, so the reference is not missing. But a reader who follows only the title and the href cannot corroborate 328.4.
- Fix: replace lines 34-36:
- title: CBO | Economic Projections | January 2025
# 2026: Sheet 2. Calendar Year, Row 53, CPI-U 328.446 (Row 51 in the original January 2025 release, before CBO's April 30, 2025 update)
href: https://www.cbo.gov/system/files/2025-01/51135-2025-01-Economic-Projections.xlsxOptional, the pinned CSV (it exists at 284a956):
- title: CBO | Economic Projections | January 2025, calendar-year CSV (variable cpiu)
href: https://github.com/US-CBO/cbo-data/blob/284a95665f9f2f74ed1f482feb629b43fce323da/data/economic/economic_projections/calendar_2025-01.csvSA4. The new Tax Parameters reference is a landing page, not the February 2026 file.
- Where:
gov/irs/payroll/social_security/cap.yaml:94-95andgov/ssa/nawi.yaml:107-108. The PR added both entries. - What is wrong: the title says "February 2026", but
https://www.cbo.gov/publication/53724redirects (301) tohttps://www.cbo.gov/data/budget-economic-data#10, which lists 13 Tax Parameters vintages from 2018 to 2026. The target changes when CBO publishes a new vintage. Incap.yamlthe PR replaced a direct file link with a row (January 2025 file, "Row 161") with this less specific link. The PR body says that cbo.gov blocks scripts, but the file URL is the link that the index page shows, so you can cite it without a download. The series is in sheet "1. Tax Parameters", row 155, "Maximum taxable earnings for the Social Security payroll tax" (2027 191,100 to 2036 258,600), and it equals the pinned CSV. - Severity: the pinned CSV in the same block corroborates every value, so this is a reference-format issue, not critical.
- Fix: in both files, replace the two lines:
- title: CBO | Tax Parameters and Effective Marginal Tax Rates | February 2026
# Sheet: 1. Tax Parameters, Row 155: Maximum taxable earnings for the Social Security payroll tax
href: https://www.cbo.gov/system/files/2026-02/53724-2026-02-Tax-Parameters.xlsxSuggestions
G1. Load CBO's calendar-2036 CPI-U and chained CPI-U points, or state the scope limit. gov/bls/cpi/cpi_u.yaml:1375-1376, gov/bls/cpi/c_cpi_u.yaml:334-335, U:1014-1032, T:468-471, T:485-486.
- Each February instant holds CBO's calendar-year average for the same year: 2035-02-01 = 407.3 = calendar 2035 (407.346). The "# 2036 value" label names the tax year that the point feeds, as the docstring of
get_projected_cpi_u_for_month(U:410-421) says. The cited data has calendar 2036 (CPI-U 416.542, chained 223.479; workbook "2. Calendar Year" rows 53 and 57), but the 2036-02-01 instant is extrapolated: 416.399 (-0.034%) and 223.586 (+0.048%). HHS 2036 already uses 416.542, so the model holds two 2036 CPI-U projections. - A probe that loads the two points changes no value read on January 1, 2036, so the PR's design holds for tax year 2036. Readers inside calendar 2036 move by at most 0.37% (one cent in a school-meal rate; also 629 Arkansas tax-table cells and 51 WIC amounts). From 2037, 743 values move, for example the Louisiana standard deduction (+0.10%). The long-run growth after the last point rests on two one-decimal values (407.3 / 398.4 = 2.234% against CBO's 2.258%). The comments at
U:1014-1016andT:468and the PR-body sentence "every refreshed series is CBO-based through 2036" are true only for tax years. - Fix, option A (preferred; a mutation test passes 40 of 40 when
T:485-486change to 2036). Incpi_u.yaml:
2035-02-01: 407.3 # 2036 value.
2036-02-01: 416.5 # 2037 value.
# Values for 2037-2100 are set programmatically in uprating_extensions.pyIn c_cpi_u.yaml, add 2036-02-01: 223.5 # 2037 value. and the same trailing comment. In U:1014-1032, set both last_projected_year=2036 and use this comment:
# CPI-U (February values, last projection year 2036). Each February
# instant holds CBO's February 2026 calendar-year average for that year
# (the "# YYYY value" comments name the tax year it feeds), so CBO's last
# point, calendar 2036, sits at the 2036 instant.Change T:485-486 to 2036, and add assert parameters.gov.bls.cpi.cpi_u("2036-02-01") == 416.5 and assert parameters.gov.bls.cpi.c_cpi_u("2036-02-01") == 223.5 at T:470-471. Optional: IRS_LAST_PROJECTED_YEAR = 2037 with T:480 at 2037 (IRS 2037 moves +0.008%, and 6,355 IRS-uprated values move).
- Fix, option B (comments only). At
U:1014-1016:
# CPI-U (February values, last projection year 2035). Each February
# instant holds CBO's calendar-year average for that year; the 2035
# instant (calendar 2035) feeds tax year 2036. CBO's calendar-2036 point
# is not loaded, so the 2036 instant and later ones are extrapolated.In the PR body, write "CBO-based for values read in 2036; CPI-U and chained CPI-U are extrapolated from the February 2036 instant".
G2. Say in the HHS index file that it runs one year ahead of 42 U.S.C. 9902(2). gov/hhs/uprating.yaml:3, :8-10; gov/hhs/fpg.yaml:132.
- 42 U.S.C. 9902(2) uses the CPI-U change "during the annual or other interval immediately preceding the time at which the revision is made". The five HHS notices from 2022 to 2026 state that interval as calendar years Y-2 to Y-1 (2026: a 2.63% increase between calendar years 2024 and 2025, FR 2026-00755). The repo grows guideline year Y by CY(Y) / CY(Y-1).
- A back-cast probe from the 2022 guidelines reproduces the published 2023-2026 4-person guidelines within 0.10% with the statutory lag. With the repo mapping it misses by -3.7% to -5.6%. With the lag, the 2027 4-person guideline is about $34,011, not $33,841 (-0.50%), and the ERDC 2027 limit is $3,718, not $3,699.
- The mapping dates from #5911 (April 2025). The PR applies it correctly and narrows the gap (before the PR: -0.70%). The fix changes a shared index, so it belongs in its own PR (see Out of scope). In this PR, replace line 3:
# Actuals: calendar-year average CPI-U for the labeled year.
# NOTE: 42 U.S.C. 9902(2) and the HHS notices update guideline year Y by CPI-U
# CY(Y-1)/CY(Y-2). gov/hhs/fpg.yaml uprates guideline year Y with this index by
# CY(Y)/CY(Y-1), one year ahead of the statute (tracked in #<follow-up issue>).Add to metadata.reference:
- title: 42 U.S. Code § 9902(2)
href: https://www.law.cornell.edu/uscode/text/42/9902#2
- title: 2026 Annual Update of the HHS Poverty Guidelines
href: https://www.federalregister.gov/documents/2026/01/15/2026-00755/annual-update-of-the-hhs-poverty-guidelinesName the same issue in the 2026 hold comment at lines 8-10.
G3. Correct the IRS window in the new comment and in the PR body. U:939-940 says "2036 reads the 12 months ending August 2035". get_irs_cpi (U:25-33) averages August 2034 to July 2035, so IRS 2036 = 217.05 = (6 x 214.9 + 6 x 219.2) / 12. A September-August window gives 217.41. The growth still matches CBO's tax parameter for the legal window of 26 U.S.C. 1(f): the model's 2036/2035 ratio is 1.019732, and "1. Tax Parameters" row 153 gives 217.68 / 213.471 = 1.019717. The one-month offset is older than the PR and #9105 tracks it. Fix:
# 2036 averages chained CPI-U from August 2034 to July 2035 (see #9105);
# the 2035 instant holds CBO's February 2026 calendar-2035 point.In the PR-body series table, correct "chained CPI-U, 12 months ending August" in the same way. The docstring at U:26 ("Sep to Aug") has the same error. It can go with #9105.
G4. Name the sheet and row in the three Economic Projections references. gov/hhs/uprating.yaml:37-38, gov/ssa/uprating.yaml:33-34, gov/usda/snap/uprating.yaml:33-34. The hrefs open the exact file, and the pinned CSVs name the variable, so every value is reproducible. The sibling files name the row (gov/bls/cpi/cpi_w.yaml:1428, cpi_u.yaml:1394, c_cpi_u.yaml:353), and the rows are confirmed in the workbook. Fix: put a comment line between title and href. In hhs/uprating.yaml: # Sheet: 2. Calendar Year, Row 53: CPI-U. In ssa/uprating.yaml and snap/uprating.yaml: # Sheet: 1. Quarterly, Row 53: CPI-U.
G5. Document the SSA CPI-U proxy and cite the COLA statute. gov/ssa/uprating.yaml:1, :10-11, :26-36. CBO publishes no CPI-W projection, so CBO CPI-U Q3/Q3 growth stands in for CPI-W. CBO's own COLA path agrees within about 0.03 percentage points (#page=74: "2.3 percent a year from 2029 to 2036"). The file has no statutory reference. Fix: add after line 11:
# CBO's Economic Projections publish no CPI-W series, so CBO CPI-U Q3/Q3
# growth stands in for CPI-W Q3/Q3. CBO's own COLA path (2.3% a year for
# 2029-2036) agrees within about 0.03 percentage points.and add to the references:
- title: 42 U.S. Code § 415(i)
href: https://www.law.cornell.edu/uscode/text/42/415#i
- title: CBO | The Budget and Economic Outlook, 2026 to 2036 | February 2026, Chapter 3, Social Security (projected COLAs)
href: https://www.cbo.gov/system/files/2026-02/61882-Outlook-2026.pdf#page=74Optional: rename the title "Historical values" (line 27) to SSA | Cost-of-living adjustments, 1975-present. In gov/ssa/nawi.yaml:105-106, the 2027 fact sheet has no NAWI figure, and AWI.html#Series is the direct source.
G6. Say that the projected caps differ from CBO's levels by design. gov/irs/payroll/social_security/cap.yaml:64-67. The cited CSV holds CBO's own bases (2028 198,000; 2036 258,600), but the YAML holds 199,200 and 260,400, because NAWI grows from SSA's published 2025 value and CBO's 2027 base (191,100) is below the official 192,300. A reader can take this for a mismatch. Add to the comment:
# The levels sit above CBO's tp_ss_max_earnings (2036: 260_400 against
# 258_600), because NAWI grows from SSA's published 2025 value; only CBO's
# growth is used.G7. Report the long-run effect, and consider a multi-year NAWI growth rate. U:983-989, gov/ssa/nawi.yaml:94-95, PR body. From 2035, NAWI, the cap and the wage-indexed amounts grow at 258,600 / 250,500 = 3.234%, the ratio of two bases that CBO rounds to $300. CBO's year-to-year base growth for 2029-2036 moves between 3.19% and 3.79%, and the 4-year geometric mean is 3.30%. Against the merge base, NAWI in 2100 is 11.0% lower (804,774 against 904,606) and the cap 10.8% lower. The 2040 PIA bend points are 2,059 and 12,414 against 2,094 and 12,624. Before the PR the same one-step method gave 3.40%. No legal rule applies. Suggestion: add 2050 and 2100 rows to the PR-body tables. Optionally, use an annualized multi-year rate. extend_parameter_values takes one ratio today (U:742-745), so a multi-year rate needs a root.
G8. Derive the nine end years from the YAML. U:941, 964, 973, 985, 996, 1008, 1019, 1028, 1038. The CPI-U overwrite that this PR fixes came from an end year that fell behind the YAML. Other extenders in the same file take the boundary from the data (first_projected_year = 1 + max(...) at U:166-168). Suggestion: take last_projected_year from the last values_list instant at the series' month, and the IRS year from the last chained CPI-U February instant plus 1. Until then, the SA2 block catches a stale constant.
G9. Confirm the Trustees 2025 scenario horizon. policyengine_us/reforms/ssa/trustees_2025.py:19 and :121 (NAWI start_year 2034), :200 (cap last_projected_year=2035). The file is outside the diff, but the PR moves the CBO horizon under it. CBO-based NAWI now runs through 2034 and the cap through 2036, so the scenario now replaces CBO's 2034 NAWI (98,514.73) and the 2036 cap. The pair is consistent with itself. Confirm that this is the intent, or set start_year to 2035 at :19 and :121 and last_projected_year=2036 at :200 (the SOI projection at :151 already uses 2036).
G10. Tighten three test details.
T:511: add 2037, the first year that reads an extrapolated NAWI (2038 before the PR):for year in [2027, 2036, 2037, 2050, 2100]:.T:466: name the June 2026 actuals, as the dicts atT:416-427do, for exampleJUNE_2026_CPI_W = 327.075 # BLS CWUR0000SA0andJUNE_2026_CPI_U = 333.952 # BLS CUUR0000SA0.T:419-474: SSA, SNAP and HHS 2028-2034 and CPI-W 2035-05-01 to 2036-08-01 are not compared with CBO. A loop over the full CBO column covers them. Theapprox(abs=5e-4)checks mean "correctly rounded", and SNAP October 2036 (419.4475008) passes by 8e-7. Exact== round(expected, 3), as in SA2, states the intent.
G11. Add the derivation to ERDC Case 2. policyengine_us/tests/policy/baseline/gov/states/or/delc/erdc/integration.yaml:38-64. The case is still at the strict limit, but it only pins "limit <= 3,699". If a later refresh lowers HHS 2027, the case still passes, but no longer at the limit. Add above the case:
# 2027 2-person FPG = (15,960 + 5,680) x 336.766 / 328.4 = 22,191.28.
# Initial limit = ceil(22,191.28 / 12 x 2) = ceil(3,698.55) = 3,699. The rule
# is income < limit, so income of 3,699 is ineligible.Optional: add a 2027-01 case at 3,698 (eligible) to or_erdc_income_eligible.yaml, which already pins the 2026 pair 3,606 / 3,607. Run it before you commit it. The output or_erdc_countable_income: 3_699 (line 61) echoes the input and checks nothing; that is older than the PR.
G12. Make the AB 2591 header add up. policyengine_us/tests/policy/contrib/states/ca/ab2591/ca_ab2591.yaml:5-10. 16,367 + 5,825 = 22,192, not 22,191, and 16,367 + 3 x 5,825 = 33,842, not 33,841. The model uses the unrounded parts (16,366.58 and 5,824.70), so the outputs are right. Fix:
# 2027 federal poverty guidelines (CONTIGUOUS_US), 2026 values x 336.766 / 328.4:
# first person = $16,366.58
# additional person = $5,824.70
# 1-person FPL = $16,367 (rounded)
# 2-person FPL = $22,191 (rounded)
# 4-person FPL = $33,841 (rounded)G13. Drop one trailing zero. gov/usda/snap/uprating.yaml:14: write 2028-10-01: 350.71 # 2028Q2: 333.952 * 347.303 / 330.708. The parameter rule says no trailing zeros. The sibling CPI-W file keeps fixed precision (376.250), so this is cosmetic. Keep 95_429.00 at gov/ssa/nawi.yaml:94: that file uses SSA's two-decimal form for every value (27_426.00 at line 49), and 95_429 would load as an integer.
G14. Correct one PR-body number. The sentence "With levels, the 2028 COLA would be 1.62% against CBO's 2.49%" does not reproduce. A probe over 6 CBO levels and 8 CPI-W/CPI-U ratios finds no 1.62%. The natural reading, CBO 2027Q3 CPI-U 341.281 x 327.075 / 333.952 = 334.253 over the 2026Q3 CPI-W 328.746, gives 1.68%. The 2.49%, 2.96% and 3.61% in the same paragraph reproduce. Fix: write "1.68% (CBO's 2027Q3 CPI-U 341.281 x 327.075 / 333.952 = 334.253, over the 2026Q3 CPI-W 328.746)", or give the formula behind 1.62%.
Investigated and cleared
- SNAP description "approximates that uprating via CPI-U" (
gov/usda/snap/uprating.yaml:1). It is accurate. USDA reprices the Thrifty Food Plan market basket with CPI-U food and item indexes (FNS monthly cost reports) and sets the maximum allotment at the June TFP cost, rounded down (7 CFR 273.10(e)(4)(ii)). FY2026 $994 and FY2027 $1,023 match the TFP cost. The all-items CPI-U would give $1,001 and $1,029. CBO projects only all-items CPI-U, so the index approximates in actual and projected years. A proposal to say that only the projections approximate was rejected. Optional: write the description as one sentence that spells out the program name. - HHS 2026 hold at 328.4. The YAML and the PR body document it. It keeps the Head Start and Early Head Start partner pins. FPG growth from 2027 does not change (it is a ratio to 2026). Only Head Start and Early Head Start spending from 2026 is about 1.0% low. No legal rule sets this level. It goes into the HHS follow-up issue.
- NAWI vintage pairing. The back-out divides by CBO's own 2027 base (191,100), not the official 192,300. This keeps CBO's growth on one vintage. The $300 rounding moves each ratio by at most about 0.08% and does not compound.
- NAWI 2035 removal. The cap, the wage-indexed amounts, the overtime thresholds and
ss_aimeread the extrapolated value after the NAWI extension runs. None treats it as a CBO point. The cap metadatauprating: gov.ssa.nawi(cap.yaml:81) has no effect, because the extension writes every year through 2100. - IRS 2036 value. It is 217.05, not 217.408. A value proposed during the review assumed a September-August window, and it fails on the real code.
- CPI-W after 2036Q4. The annual February extension gives +1.12% from August 2036 to August 2037. The CPI-W level in 2027Q3 is 0.8% below the SSA uprater (334.253 against 336.945). The only reader, the Washington millionaires deduction, takes a 12-month ratio, and its 2028-2040 values are the same at the base and the head.
snap_max_allotment.yamlperiod2027-11(older, unchanged). The variable is MONTH-defined and the case needs FY2028. It passes in CI and locally.- ERDC Case 2 input moved with its output. This was necessary (3,692 would now be eligible), and the case is still at the strict limit.
- Partner contract tests. No
partners/**file is edited, and no partner test has a period after 2026. The HHS 2026 hold keeps the Head Start pins, and all 623 partner tests pass. This PR has no partner-facing change. - Severity disputes. The SNAP citation stays critical, because the PR edits that reference block and the fix is metadata only. The HHS lag is a pre-existing method issue: a note in this PR (G2) and a fix in a follow-up. The cap extension is should-address, not a suggestion: it contradicts a clear rule, and its docstring claims to follow the statute. The CPI-U 2036 instant is a suggestion, because no value read on January 1, 2036 changes. The missing sheet and row are a suggestion (the hrefs open the exact file), and the landing-page href is should-address. The test gaps in SA2 are should-address: the mutation tests show that a 1% error at the seam passes all 40 tests.
Out of scope / follow-up
- "Federal poverty guideline projections lead the 42 U.S.C. 9902(2) CPI-U interval by one year" (pre-existing since #5911; include the 2026 hold). Designs: A, redefine
gov.hhs.upratingso that instant Y holds CY(Y-1); B, a new FPG-only lagged index forgov/hhs/fpg.yaml:132; B', cadence metadata onfpg.yamlwith 2026-2036 at CBO levels. Design B leaves the Head Start and Early Head Start partner pins unchanged. Designs A and B' move those partner pins (A: 2025 +1.46%, 2026 +2.07%). That is a partner-facing change, and it needs the partner gate before anyone edits a partner file. Under every design, the 2027 ERDC and AB 2591 expectations move. - "get_irs_cpi averages August-July, not the 12 months ending August": #9105 tracks it.
- "CPI-U and chained CPI-U February points are calendar-year averages, not 12 months ending August": #9608 tracks it.
- "Round projected SNAP maximum allotments down to the dollar (7 CFR 273.10(e)(4)(ii))": FY2028 is 1,049.42, and the rule gives 1,049.
- "Round projected Social Security COLA steps to 0.1 percent (42 U.S.C. 415(i)(1)(D))": the 2028 step is 2.494%, and the statutory COLA is 2.5%.
- "Index the SNAP standard deduction to CPI-U for items other than food (7 U.S.C. 2014(e)(1)(A)(ii)(II))": it uses the TFP-based SNAP index today, as do the shelter cap and the utility allowances.
- "Remove the stale January 2025 CBO reference from cpi_w.yaml" (
gov/bls/cpi/cpi_w.yaml:1424-1426): it supports no current value, and "Row 51" is stale since CBO's April 30, 2025 update. - "Fix CBO reference titles in cpi_u.yaml that name Tax Parameters but link Economic Projections files" (
gov/bls/cpi/cpi_u.yaml:1384-1391).
Data Audit Summary
The PR cites no PDF for a value, so this table replaces the PDF audit. All values were recomputed from the cbo-data CSVs at 284a956, which equal the CBO workbook rows, and from the BLS and SSA series.
| Group | Checks | Formula or source | Result |
|---|---|---|---|
| Anchors | 15 | BLS CPI-W and CPI-U June and Q3 2026; SSA NAWI 2025 and 1992, CBB 1994, 2026 and 2027; CBO 2027 base and 2026 CPI-U bases; CBO January 2025 calendar 2026 (328.446) | Match |
| SSA uprating 2028-2036 | 9 | 328.746 x CBO CPI-U Q3(Y-1) / 332.976 ("1. Quarterly", row 53) | 9 of 9 |
| SNAP uprating October 2027-2036 | 10 | 333.952 x CBO CPI-U Q2(Y) / 330.708 (row 53) | 10 of 10 |
| HHS uprating 2027-2036 | 10 | 328.4 x CBO calendar CPI-U(Y) / 331.807 ("2. Calendar Year", row 53) | 10 of 10 (same-year mapping, G2) |
| NAWI 2026-2034 | 9 | 72,800.33 x CBO base(Y+2) / 191,100 ("1. Tax Parameters", row 155) | 9 of 9 |
| Payroll cap 2028-2036 | 9 | 430(b): 60,600 x NAWI(Y-2) / 22,935.42, nearest $300 | 9 of 9, no $150 tie |
| CPI-W 2035-05-01 to 2036-11-01 | 7 | CBO CPI-U quarter x 327.075 / 333.952 | 7 of 7 |
| Test constants | 14 | CSV values and literals in T |
14 of 14 |
| Moved YAML test values | 7 | ERDC Case 2, SNAP FY2028, AB 2591 1, 2 and 4 persons, and the two AB 2591 header components | Match |
| PR-body tables | 108 | 98 checkable rows of the nine 2027-2037 tables, the IRS 2027 row and the nine 2036 rows; parameter tree probe at the head and the merge base | Match |
| CSV against workbook (not counted) | 85 points | 56 quarterly, 14 calendar, 15 tax-parameter | 0 differences |
| PR-body narrative (not counted) | 8 | 2.96%, 3.61%, 2.49%, 0.46%, 2.58%, 331.3 and +0.89% reproduce; "2028 COLA would be 1.62%" does not | 7 match, 1 not reproduced (G14) |
Tally: 198 checks match, 0 mismatch. Every comment formula in the changed YAML recomputes. Of 33 references checked, 24 are correct, 4 are wrong (C1, SA3, and SA4 in two files) and 5 were not checked (none supports a changed value). Three Economic Projections references name no sheet or row (G4).
Validation Summary
| Check | Result |
|---|---|
| CI | 27 pass, 0 fail at 493ec45c8a |
| Local tests | test_uprating_extensions.py 40/40; ERDC integration 14/14; snap_max_allotment.yaml 4/4; ca_ab2591.yaml 8/8 |
| Partner contract tests | No partner file touched. Read-only run of all partner tests: 623/623 pass |
| Regulatory | 1 critical (C1, SNAP citation); 1 should-address (SA1, cap extension); HHS lag pre-existing (G2 and a follow-up) |
| References | 33 checked: 24 correct, 4 wrong (C1, SA3, SA4 x2), 5 not checked |
| Code patterns | No formula changed. End years match the YAML. Changelog fragment correct. One trailing zero (G13) |
| Tests | 2 new tests and 1 changed check. The seam points and the "starts early" case are not pinned (SA2) |
| Mutation | 26 mutants. 6 one-percent seam errors pass all 40 tests (SSA 2100 -47.1%). 9 of 9 "starts early" mutants pass the parametrized test. The SA2 block kills every survivor. The SA1 fix gives 0 of 64 years off 430(b) |
| Probes | Full parameter tree at the head and the merge base; loading CBO's 2036 CPI points changes 0 values read on January 1, 2036; HHS back-cast 2023-2026 |
| Branch | 3 ahead / 47 behind main; MERGEABLE. Merge hold until spm-calculator 1.1.0 |
| Other reviews | Author comment only: a local run of the 261 future-year YAML files stopped after 3; CI covers the rest |
| Axiom line | Present: "n/a: projection data refresh, no change in law" |
Review Severity: REQUEST_CHANGES
One critical item (C1) and four should-address items (SA1, SA2, SA3, SA4) are open.
Next Steps
To auto-fix issues: run the fix-pr workflow for this PR.
- Apply C1: replace the SNAP citation at
gov/usda/snap/uprating.yaml:29-30with 2012(u)(3)(C). - Apply SA1: replace
extend_social_security_payroll_capand theT:313-318check. If you keep the function out of this PR, correct the docstring and open the follow-up issue. - Apply SA2: append the test block after
T:502. If you also take G1 option A, move the CPI-U and chained CPI-U rows one year later. - Apply SA3 and SA4: replace the HHS 2026 reference and the two Tax Parameters references.
- Take the suggestions you agree with. G1, G2 and G3 remove the most reader confusion. G4, G5, G6, G12 and G13 are comment or reference edits. G14 and part of G1 and G3 are PR-body edits.
- Run
make format, thentest_uprating_extensions.py, the three moved YAML files and the partner tests (read-only). - Open the follow-up issues in the list above. The HHS issue needs the partner gate if its design moves Head Start pins.
- Merge only after spm-calculator 1.1.0 is released.
- Cite 7 U.S.C. 2012(u)(3)(C) for the SNAP uprater, plus the pre-2025 (u)(4) and 7 CFR 273.10(e)(4)(ii). - Extend the payroll cap after 2036 with the 42 U.S.C. 430(b) fixed 1994 base instead of the chained 20 CFR 404.1048 wording; it reproduces every automatically adjusted base from 1995 to 2027. - Load CBO's calendar-2036 CPI-U (416.5) and chained CPI-U (223.5) points and start both extensions in 2037. - Pin every CBO February 2026 projection point, including the two that set the 2037-2100 growth of each series, and the IRS August-July window. - Cite the January 2025 Economic Projections file for the HHS 2026 anchor, the February 2026 Tax Parameters file for the cap and NAWI, and the sheet and row of each Economic Projections series. - Document the HHS one-year lead over 42 U.S.C. 9902(2), the CPI-U proxy for CPI-W with 42 U.S.C. 415(i), and why projected caps sit above CBO's. - Correct the IRS window comments, the ERDC, AB 2591 and 2042 dependent standard deduction derivations, and one trailing zero. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LqCGPgxDukji8Bhs57c5rH
|
Thanks, @PavelMakarchuk. All of this is in adf8982 and 241b029, after a merge of
The merge hold still applies: no merge until spm-calculator 1.1.0 is released. |
The test pins the last authored CPI-U year, which sets the default dataset extension end year; CBO's calendar-2036 point now ends the YAML. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LqCGPgxDukji8Bhs57c5rH
PavelMakarchuk
left a comment
There was a problem hiding this comment.
Program Review
PR #10227, "Load CBO's February 2026 projections through 2036 into the upraters" (DTrim99). Round 2, incremental review of the changes since my round-1 review (CHANGES_REQUESTED on 493ec45c8a).
IDs: C = critical, SA = should address, G = suggestion. Round-1 IDs keep their numbers. New items start at G15.
Paths: U = policyengine_us/parameters/uprating_extensions.py, T = policyengine_us/tests/policy/baseline/parameters/test_uprating_extensions.py. Parameter paths such as gov/ssa/uprating.yaml are under policyengine_us/parameters/. Line numbers refer to the reviewed head. PDF links use the file page number (file page = printed page + 8 in the CBO report).
Source Documents
- Same as round 1: CBO Economic Projections, February 2026 ("1. Quarterly" row 53; "2. Calendar Year" rows 53 and 57); CBO Tax Parameters, February 2026 ("1. Tax Parameters" row 155); US-CBO/cbo-data at 284a956; SSA AWI, CBB and COLA series; BLS CPI-W and CPI-U monthly through September 2026; HHS poverty guideline notices.
- Workbook, new in round 2: CBO Economic Projections, January 2025, both versions: the original release (capture of 2025-01-29, CPI-U in row 51) and CBO's April 30, 2025 update (capture of 2025-05-21, CPI-U in row 53). Calendar 2026 CPI-U is 328.446 in both. The pinned
calendar_2025-01.csvat 284a956 gives the same value. - PDF: CBO, The Budget and Economic Outlook: 2026 to 2036, file page 74 (printed 66), Chapter 3, projected COLAs. I also read the passages that date each COLA by the January in which it takes effect.
- Law: 42 U.S.C. 430(b) with the Pub. L. 103-296 sec. 321(g) amendment notes; 20 CFR 404.1048(b)(2)(i); 42 U.S.C. 415(i); 7 U.S.C. 2012(u)(3)(C); 7 U.S.C. 2012(u)(4), 2023 edition; 7 CFR 273.10(e)(4)(ii); 42 U.S.C. 9902(2); FR 2026-00755; 26 U.S.C. 1(f).
- PR body at the head (
gh pr view 10227), for G3, G7 and G14. - Access: cbo.gov still returns 403 to scripts. CBO files were read from Wayback captures and the pinned CSVs.
- Reviewed head SHA: 241b029
- Mode: incremental from 493ec45 (14 PR files, +280/-109; commits
adf8982130and241b029be6after the merge ofmaininaa09f0c40d)
Branch Status
- The branch is 6 commits ahead and 38 behind
main(0e7ced1747). The merge ofmain(52 commits, no conflicts) touched none of the 14 PR files, so every reviewed hunk is yours. The staleness did not affect any finding. - Merge condition: the PR's own hold. Do not merge until spm-calculator 1.1.0 is released (PolicyEngine/spm-calculator#51, per PolicyEngine/policyengine-api#3926). This is a merge condition, not a finding.
What round 2 fixed
Thank you for a careful round. Every critical and should-address item is resolved, and the fixes were checked independently of your own tests.
- C1, SNAP citation.
gov/usda/snap/uprating.yaml:29-30now cites 7 U.S.C. 2012(u)(3)(C). The anchor exists, and its text is the June CPI-U rule that the 10 projected values use. The two extra references (:31-34) are right for the periods they cover: the 2023-edition (u)(4) for the 2020-2024 actuals and 7 CFR 273.10(e)(4)(ii) for all years. - SA1, 430(b) fixed base.
U:778-809now applies 42 U.S.C. 430(b): max(cap(Y-1), round300(cap(1994) x NAWI(Y-2) / NAWI(1992))). It reads the 1994 base (60,600) and NAWI 1992 (22,935.42) from the tree, so no legal value is hard-coded. The docstring is accurate (430(b), 20 CFR 404.1048(b)(2)(i), Pub. L. 103-296 sec. 321(g)(1)).- An independent 430(b) table, built only from SSA and CBO constants with exact arithmetic and the $150 rule, matches the model in all 64 years from 2037 to 2100 (and in all 73 years from 2028). 2040 is 295,500 and 2100 is 1,995,300. The old chained rule differed in 44 of 64 years.
- The fixed base reproduces 30 of the 33 historical bases from 1995 to 2027. The three misses (2010, 2011, 2016) are the no-COLA freezes under 430(a). Your reply says only 2016; that is true for explicit YAML entries, and no file repeats the claim.
- The Trustees 2025 caller (
reforms/ssa/trustees_2025.py:198-202) now gives a cap that follows 430(b) on the Trustees NAWI in all 65 years from 2036 to 2100 (the old chain was off in 59). Its tests pass (200 tests with T). - The restored chained formula fails
T:322(295,800 against 295,500 in 2040).
- SA2, pinned projections.
test_upraters_encode_cbo_february_2026_projections(T:516-584, 100 cases) andtest_irs_uprating_averages_cbo_chained_cpi_u_points(T:598-610) take their expected values only from the CBO dicts and five named anchors. All 74 dict values equal the cbo-data CSVs. The exact== round(expected, n)comparison is stable: the closest case to a rounding tie (SNAP October 2036) is 8.0e-7 away, against float noise of about 6e-14. Of 38 mutants, 35 fail at least one test:- all 7 seam mutants (x1.01 on the second-to-last point), including the CPI-W 2036-02-01 mutant that moved CPI-W 2100 by +91% in round 1;
- all 8 non-equivalent "starts one year early" mutants, each by an exact pin of the last CBO point, so the kill no longer depends on CBO's last two growth rates;
- all 9 "starts one year late" mutants, the chained-cap mutant, +/-0.1 on both new 2036 points, the chained CPI-U 2034 mutant that the round-1 IRS line missed, and errors at intermediate years (SSA 2031, CPI-W 2035-08-01, NAWI 2028 and 2033).
- The survivors: the cap "starts early" mutant is equivalent (430(b) recomputes 2036 as 260,400, the YAML value), and two scenario probes belong to G8 and G17.
- SA3 and SA4, references.
gov/hhs/uprating.yaml:43-47cites the January 2025 workbook, and the row comment (row 53, row 51 before the April 30, 2025 update) matches both captures.gov/irs/payroll/social_security/cap.yaml:97-99andgov/ssa/nawi.yaml:105-107link the February 2026 Tax Parameters file. Row 155 has the cited label and all 15 values. - G1, 2036 CPI points.
gov/bls/cpi/cpi_u.yaml:1376(416.5) andgov/bls/cpi/c_cpi_u.yaml:335(223.5) are CBO calendar 2036 (416.542, 223.479) at one decimal, with the file's "# 2037 value." label convention. A full-tree probe at both heads shows:- 0 values move on January 1, 2036, and the IRS index is identical in every year;
- 698 values move inside calendar 2036 and 743 from 2037, as round 1 predicted;
- long-run growth is now closer to CBO: CPI-U 2.2588% (CBO 2.2575%), chained CPI-U 1.9617% (CBO 1.9744%);
- the default single-year dataset end year is now 2036, and
241b029updates the test that pins it.
- Suggestions done: G3 (August-July in the comment, the docstring and the PR body), G4 (row comments), G5 (proxy note, 415(i),
#page=74, retitle, fact sheet dropped), G6, G10, G11, G12, G13 and G14 (the PR body now gives 1.68% with the formula, and no 1.62% is left). The changed test comments recompute: the 2042 dependent standard deduction (223.5 x (223.5/219.2)^5 = 246.299; $1,429.85; $427.49), ERDC Case 2 (ceil(3,698.55) = 3,699) and the AB 2591 header (16,366.58 + 5,824.70 = 22,191.28). - Tests: CI passes 27 of 27. Local runs at the head pass: T and the dataset-extension tests 212, the four YAML files 46 (20 + 14 + 8 + 4), code health 452 (1 skipped) and all 623 partner tests. No partner file is in the diff. The data audit matches 289 of 290 checks. The one mismatch is a growth rate in a comment (G16).
Round-1 status
| ID | Round 1 | Status | Evidence |
|---|---|---|---|
| C1 | Critical | RESOLVED | snap/uprating.yaml:29-30 cites (u)(3)(C) #u_3_C; anchor and text confirmed; both optional extras correct for their periods |
| SA1 | Should address | RESOLVED | U:778-809 is 430(b); 0 of 64 years 2037-2100 off an independent table; Trustees path 0 of 65; chained mutant fails T:322 |
| SA2 | Should address | RESOLVED | 100-case exact pins (T:516-584) and the IRS test (T:598-610); 35 of 38 mutants killed; the third survivor is equivalent |
| SA3 | Should address | RESOLVED | hhs/uprating.yaml:43-47; rows 51/53 and 328.446 confirmed in both workbook versions; pinned CSV exists |
| SA4 | Should address | RESOLVED | cap.yaml:97-99, nawi.yaml:105-107 link the February 2026 file; row 155 label and values confirmed |
| G1 | Suggestion | RESOLVED (option A) | 416.5 and 223.5 loaded; 0 values move on 2036-01-01; IRS unchanged. Declining IRS_LAST_PROJECTED_YEAR = 2037 (+0.008%) is defensible |
| G2 | Suggestion | PARTIAL | NOTE and both references correct; "a separate PR" names no issue, and none exists |
| G3 | Suggestion | RESOLVED | U:26-30 docstring, U:938-939 comment and PR-body table say August-July with #9105 |
| G4 | Suggestion | RESOLVED | Row comments at hhs/uprating.yaml:49, ssa/uprating.yaml:40, snap/uprating.yaml:38 match the workbook rows |
| G5 | Suggestion | RESOLVED (one figure, G16) | Proxy note, 415(i) #i, #page=74 (printed 66), retitle, fact sheet dropped from nawi.yaml |
| G6 | Suggestion | RESOLVED | cap.yaml:68-70: 260,400 against CBO 258,600 is correct |
| G7 | Suggestion | PARTIAL; deferral defensible | PR-body long-run figures reproduce (NAWI 2100 804,773.88; cap 1,995,300; 2040 bend point 2,059); multi-year rate left for a follow-up |
| G8 | Suggestion | DECLINED (deferred); defensible | Literals stay at U:940, 963, 972, 984, 995, 1007, 1019, 1028, 1038. The pins catch only the "one year early" direction (see G17) |
| G9 | Suggestion | DECLINED (deferred); defensible | trustees_2025.py:19, 121, 200 unchanged; scenario consistent with itself; SA1 makes its cap follow 430(b) |
| G10 | Suggestion | RESOLVED | 2037 in the wage-indexed list; named anchors T:509-513; full columns with exact rounding |
| G11 | Suggestion | RESOLVED | Derivation at erdc/integration.yaml:38-40 recomputes; skipping the optional 3,698 case is defensible |
| G12 | Suggestion | RESOLVED | ca_ab2591.yaml:5-10 adds up |
| G13 | Suggestion | RESOLVED | snap/uprating.yaml:14 is 350.71 (same float) |
| G14 | Suggestion | RESOLVED | PR body gives 1.68% with the formula; "1.62" occurs 0 times |
Tally: 15 resolved, 2 partial (G2, G7), 2 declined with defensible reasons (G8, G9). No round-1 critical or should-address item is open.
Critical (Must Fix)
None.
Should Address
None.
Suggestions (new in round 2)
G15. The 430(b) $150 tie rule that the new docstring states has no test.
- Where:
U:767-775(round_social_security_amount, tie branchif fractional < 0.5atU:773), used for the cap atU:800. The new docstring atU:788-789says "a multiple of $150 rounds up". T has no assertion at an exact tie. - Evidence: the code is correct. 42 U.S.C. 430(b) rounds a product that is a multiple of $150 but not of $300 to the next higher multiple of $300. But two mutants pass all 141 tests in T and 163 other cap and CPI tests:
fractional < 0.5changed tofractional <= 0.5(a tie rounds down);round_social_security_amountchanged toround(amount / increment) * increment(Python's round-half-to-even, a plausible simplification).
The cap checks atT:312-322,T:332-350andT:587-596compute their expectations with the same helper, so they move with it.
- Why only a suggestion: the helper is older than the PR (#7912, #8335), and the PR does not change it. Every extended cap went through this branch before the PR too. No projected product is near a tie: the closest is 2061 on the CBO path ($0.72 away) and 2066 on the Trustees path ($0.65). Both mutants change 0 of 1,386 Social Security values (the cap, the wage base and the wage-indexed amounts, 2024-2100, on the CBO and Trustees paths).
- Fix: append after
T:350. All three lines pass at the head. The first line kills the tie-down mutant, and the second kills the round-half-to-even mutant (60,450 / 300 = 201.5 rounds to the even 202 under both rules, so it cannot catch that mutant).
def test_social_security_payroll_cap_rounds_150_ties_up():
"""42 U.S.C. 430(b): a multiple of $150 (but not of $300) rounds up."""
assert round_social_security_payroll_cap(60_450) == 60_600
assert round_social_security_payroll_cap(60_150) == 60_300
assert round_social_security_payroll_cap(60_449.99) == 60_300G16. The SSA proxy note gives 2.26% a year where CBO's span gives 2.27%.
- Where:
gov/ssa/uprating.yaml:12-15(new inadf8982). - Evidence: CBO dates each COLA by the January in which it takes effect (Outlook: "the 2.8 percent COLA effective in January 2026"). Its "2.8 percent a year from 2026 to 2028" (#page=74) reproduces only on that dating: 2.8, 3.00 and 2.49 average 2.76%; December dating gives 2.61%. So "2029 to 2036" means the 8 COLAs effective January 2029 to January 2036. This file dates its values the same way (
2029-01-01: 344.854 # 2028Q3). Their mean is (403.287 / 336.945)^(1/8) - 1 = 2.272%. The figure 2.26% is the 7-COLA mean from January 2030 ((403.287 / 344.854)^(1/7) - 1 = 2.261%), which leaves out the January 2029 step (2.347%). Round 1 also gave 2.27%. - Effect: none on values. Both figures round to CBO's 2.3%, so the conclusion of the note holds.
- Fix: replace lines 12-15:
# CBO's Economic Projections publish no CPI-W series, so CBO CPI-U Q3/Q3
# growth stands in for CPI-W Q3/Q3. CBO's own projected COLAs (2.3% a year
# for the COLAs effective January 2029 to January 2036) match this growth
# (2.27% a year) to the tenth of a percent that CBO publishes.G17. No test stops a later YAML point from being overwritten by a stale end-year constant (the remaining G8 risk).
- Where: the
last_projected_yearconstants atU:963, 972, 984, 995, 1007, 1019, 1028, 1038; no guard in T. - Evidence: your reply says that the full-column pins now catch a stale end year. They catch an end year that is one year early, because the last CBO point then fails its exact pin. They do not catch the round-1 bug class, a YAML that moves past the constant. Two probes on copies:
gov/ssa/uprating.yamlgets2037-01-01: 415.000, and the SSA constant stays 2036. T passes 141 of 141. The extension overwrites the new point with 412.390.gov/bls/cpi/cpi_u.yamlgets2037-02-01: 430.0, and the CPI-U constant stays 2036. T passes 141 of 141. The point becomes 425.908.
The pins would catch this only if the refresher also extended the dicts and the hard-coded loops (range(..., 2037)atT:521, 527, 533, 556, 607,range(2026, 2035)atT:551).test_upraters_extrapolate_only_after_cbo_projectionscannot catch it, because the overwrite makes every later growth rate equal.
- Fix (test only; deriving the constants from the data, as G8 proposed, can stay a follow-up): add
import datetimeto the imports, and append afterT:640. The test restates no end year: every value authored in a YAML file must survive the extension. It passes 8 of 8 at the head. It fails the matching row in both probes above, and it also fails an SSA "starts one year early" mutant (at 2036-01-01). It does not coverIRS_LAST_PROJECTED_YEAR(U:940), which selects points instead of overwriting them;T:598-610pins that for this vintage.
EXTENDED_SERIES = [
"gov.ssa.uprating",
"gov.usda.snap.uprating",
"gov.hhs.uprating",
"gov.ssa.nawi",
"gov.irs.payroll.social_security.cap",
"gov.bls.cpi.cpi_u",
"gov.bls.cpi.c_cpi_u",
"gov.bls.cpi.cpi_w",
]
@pytest.mark.parametrize("path", EXTENDED_SERIES)
def test_extension_keeps_every_authored_value(path):
"""The extensions must not overwrite any value written in the YAML file."""
parameter = PARAMETERS.get_child(path)
with open(parameter.file_path) as f:
authored = yaml.safe_load(f)["values"]
for date, value in authored.items():
if isinstance(value, dict):
value = value["value"]
instant = date.isoformat() if isinstance(date, datetime.date) else str(date)
assert parameter(instant) == pytest.approx(value, abs=1e-9), instantG18. Some new pins sit at projection instants that the next BLS refresh writes over.
- Where: the CPI-W cases from 2026Q3 (
T:536-549,if quarter < "2026Q3"atT:539), the CPI-U and chained CPI-U cases from 2027 (T:554-567) and the IRS years from 2029 (T:607). - Evidence: the refresh protocol in the docstring of
get_average_for_12_months_ending_august(U:47-49) replaces a projection instant with the observed value, and #9100 did exactly this for CPI-W and CPI-U in 2026. Two simulated refreshes on copies:- Loading the published July-September 2026 CPI-W (327.104, 328.481, 330.654, the values that
gov/ssa/uprating.yaml:9already uses) fails 1 case:cpi_w@2026-08-01(pinned 326.119, observed 328.481). - A refresh that reaches February 2027 fails 3 tests:
cpi_u@2027-02-01,c_cpi_u@2027-02-01, and the IRS test, whose 2029 line reads the 2027 chained point. - If a refresher also re-anchors CPI-W at a newer actual, all 42 CPI-W cases fail, because
JUNE_2026_CPI_WandJUNE_2026_CPI_U(T:510-511) are fixed.
- Loading the published July-September 2026 CPI-W (327.104, 328.481, 330.654, the values that
- This is not a defect. Every pin is correct today, and a refresh makes the tests fail loudly, never pass silently. The failure message does not name the cause, so a short note helps the next refresher. Do not make the loops derive their start from the YAML: a stray monthly value would then skip cases silently.
- Fix: extend the two docstrings. In
test_upraters_encode_cbo_february_2026_projections(T:578-583):
"""Each projected value applies CBO's February 2026 growth to its anchor.
extend_parameter_values grows every year after a series' last CBO point at
the ratio of its last two points, so these values, the last two included,
also set the 2037-2100 path.
A monthly BLS refresh writes observed values over projection instants (see
get_average_for_12_months_ending_august). When it does, start the CPI-W
cases after the last observed quarter and the CPI-U and chained CPI-U cases
after the last observed February, and update JUNE_2026_CPI_W and
JUNE_2026_CPI_U if the projections are re-anchored.
"""In test_irs_uprating_averages_cbo_chained_cpi_u_points (T:599-602):
"""IRS(Y) averages chained CPI-U from August Y - 2 to July Y - 1 (#9105).
Six months read the February Y - 2 point and six read February Y - 1.
A BLS refresh that writes an observed February over a projection point
changes the IRS years that read it; drop those years from the loop.
"""Optional: start the CPI-W cases at 2026Q4 now, because 2026Q3 is already published.
G19. The changelog does not say that single-year datasets now extend through 2036 by default.
- Where:
changelog.d/cbo-2026-projections-2036.changed.md. The behavior is inpolicyengine_us/data/economic_assumptions.py:74-78(the default end year is the last authored CPI-U year), reached frompolicyengine_us/system.py:493and:505. - Evidence: the new
cpi_u.yaml2036 point moves the default from 2035 to 2036. AMicrosimulation()on the default dataset now builds 13 yearly frames (2024-2036) instead of 12, and 2036 can be calculated withoutdataset_end_year. The design is deliberate, the PR body says so, and241b029updates the test. Downstream users (API, app) read the changelog, which does not mention it. - Fix: replace the fragment text with:
Load CBO's February 2026 projections through 2036 into the SSA, SNAP and HHS upraters, the CPI-W series, the national average wage index and the Social Security payroll cap, growing each from its latest actual (the HHS index from its 2026 value); keep CBO's 2035 CPI-U and chained CPI-U points instead of extrapolating over them and add their 2036 points; extend the payroll cap after 2036 with the 42 U.S.C. 430(b) fixed-base formula; and extend single-year datasets through 2036 by default.
Optional: the mock constant END_YEAR_DEFAULT = 2035 in policyengine_us/tests/microsimulation/data/fixtures/test_extend_single_year_dataset.py:20 (older than the PR) no longer equals the real default. It is only passed as an explicit end_year, so a rename such as END_YEAR_EXPLICIT is enough.
Still open or declined from round 1
- G2 (partial). The NOTE at
gov/hhs/uprating.yaml:4-7and the 9902(2) and FR 2026-00755 references are correct. But "a separate PR" names no issue, and no issue exists, so the deviation from 42 U.S.C. 9902(2) and the end of the 2026 hold have no tracking. Fix: open "Federal poverty guideline projections lead the 42 U.S.C. 9902(2) CPI-U interval by one year" (see Out of scope) and name it. At line 7, write# shared index, so it is tracked in #<issue>.; at lines 13-14, write(#<issue> on the statutory lag above would revisit it). - G7 (partial; deferral defensible). The long-run reporting is done and reproduces. No legal rule governs projected wage growth, so the multi-year rate can be a follow-up. Optional: one sentence on the sensitivity at
U:978-988orgov/ssa/nawi.yaml:95, so that the note is also in the code. - G8 (declined; defensible as a refactor). Every current value is correct. The remaining risk is a future refresh; G17 covers it with a test.
- G9 (declined; defensible). The scenario horizon is a design choice for the owner of #8220. A related pre-existing gap is listed in Out of scope.
Investigated and cleared
- G1 side effects. The IRS index reads chained CPI-U only through July 2035, so it does not move. Readers inside calendar 2036 move by at most 0.37% (one cent in a school-meal rate; 629 Arkansas table cells by +0.024%). The Louisiana standard deduction is +6.45% by 2100, because
get_la_cpi_u_percentage_increaserounds the yearly CPI-U increase to 0.1 point: the new long-run step (2.2588%) rounds to 2.3%, as CBO's exact 2.2575% does. The dependent standard deduction moves from 2045 (2100: 6,100 to 5,950) and the earned-income add-on from 2059. The 2042 YAML case does not move: its increase of $1,429.85 sits between the $1,400 and $1,450 steps. - One-decimal CPI storage. Three-decimal 2035 and 2036 points would move about 6,450 values from 2036, because the IRS index reads the 2035 point. That belongs to a later vintage, not this PR.
- 430(a) trigger. A new base is determined only in a year with an automatic COLA. The projected SSA steps are 2.26-2.35% through 2036 and 2.257% after, so the trigger never binds. Optional: one docstring sentence.
- Exact pins and ties. The exact comparisons are stable on any IEEE-754 platform. After a later CBO refresh, a change of about 1e-6 in an input can flip a near-tie case (SNAP October 2036). That is a correct failure, not a flaky test.
- References, minor.
#page=74holds every cited figure; the sentence starts on file page 71, so#page=71with "#page 71-74" in the title is optional. The eCFR short URL redirects (302) and keeps the fragment.gov/hhs/uprating.yaml:44writes "Sheet 2. Calendar Year" without the colon that the sibling comments use. The docstring cites sec. 321(g)(1) and the PR body (1)(A); both are fine. - Partner contract tests. No
partners/**file is in the diff, and all 623 partner tests pass. This round has no partner-facing change.
Out of scope / follow-up
- "Federal poverty guideline projections lead the 42 U.S.C. 9902(2) CPI-U interval by one year" (pre-existing since #5911; include the 2026 hold). Designs A and B' move the Head Start and Early Head Start partner pins, so they need the partner gate. Name this issue in the G2 comments.
- "Trustees 2025 scenario: confirm the horizon and re-derive the wage base and wage-indexed Social Security amounts from the Trustees NAWI" (#8220, #9526; G9).
apply_trustees_2025_economic_assumptions(trustees_2025.py:191-202) reruns the cap extension but notextend_social_security_wage_indexed_parameters(U:812-920). In the Trustees tree,gov.ssa.social_security.wage_basediffers from the cap in all 65 years from 2036 to 2100 (2036: 260,400 against 261,900; 2100: 1,995,300 against 2,454,900), and the 2040 bend point 1 stays 2,059 (2,107 on the Trustees NAWI). The prior head had the same split, so this PR did not cause it. Fix: call the wage-indexed extension after the cap extension, and assertwage_base == capfor 2036 and 2100. - #9105:
get_irs_cpiaverages August-July, not the 12 months ending August. - #9608: CPI-U and chained CPI-U February points are calendar-year averages; the older comment at
c_cpi_u.yaml:324-325says "12mo ending August". - G7 and G8 follow-ups: a multi-year NAWI growth rate; end years derived from the data.
- Unchanged from round 1: round projected SNAP allotments down to the dollar (7 CFR 273.10(e)(4)(ii)); round projected COLA steps to 0.1% (42 U.S.C. 415(i)(1)(D)); index the SNAP standard deduction to CPI-U for items other than food; remove the stale January 2025 reference in
cpi_w.yaml:1424-1426; fix the Tax Parameters titles on Economic Projections links incpi_u.yaml.
Data Audit Summary
The PR cites no PDF for a value, so this table replaces the PDF audit. All values were recomputed from the cbo-data CSVs at 284a956 (equal to the workbook rows), the BLS and SSA series, and an independent 430(b) implementation.
| Group | Checks | Formula or source | Result |
|---|---|---|---|
| Round-2 values and comment numbers | 30 | 2036 CPI points; SNAP 350.71; G6 cap figures; HHS NOTE against FR 2026-00755 and fpg.yaml; January 2025 rows 51/53 and 328.446; four sheet/row comments; IRS 2036 = 217.05; 2042 standard deduction, ERDC and AB 2591 derivations |
29 match, 1 mismatch (2.26%, G16) |
| YAML files, prior head against head | 10 | git show at both heads |
10 match: only the two new 2036 points; 350.710 to 350.71 is the same float |
| Payroll cap 2037-2100 and floor check | 65 | 430(b) in exact arithmetic on the model's NAWI | 65 match; 2100 = 1,995,300 |
| CBO test constants | 74 | Quarterly CPI-U 43, calendar CPI-U 11, chained 10, CBB 10 | 74 match |
| Named anchors | 5 | BLS CPI-W 2026Q3 and June 2026, CPI-U June 2026, SSA AWI 2025, CBO January 2025 | 5 match |
| Parametrized case values | 97 | Model value equals round(expected, n); also recomputed straight from the CSVs (3 more are in row 1) |
97 match |
| IRS 2029-2036 | 8 | (6 x C-CPI-U(Y-2) + 6 x C-CPI-U(Y-1)) / 12 | 8 match |
| Default dataset end year | 1 | Last key of cpi_u.yaml |
1 match (2036) |
Tally: 289 of 290 checks match. The one mismatch is the 2.26% rate in a comment, with no value effect. After the extensions, SSA, SNAP, HHS, IRS, NAWI and CPI-W are identical between the two heads from 1990 to 2100. The cap differs from 2040 (chained rule to 430(b)), and CPI-U and chained CPI-U differ from 2036 (G1). References: 30 checked, 30 correct; one figure in a correct comment is imprecise (G16).
Validation Summary
| Check | Result |
|---|---|
| CI | 27 pass, 0 fail at 241b029be6 |
| Local tests | T and test_extend_single_year_dataset.py 212 passed; basic_standard_deduction.yaml 20, ERDC integration 14, ca_ab2591.yaml 8, snap_max_allotment.yaml 4; code health 452 passed, 1 skipped |
| Partner contract tests | No partner file touched. Read-only run: 623 of 623 pass |
| Regulatory | C1 and SA1 resolved. Cap 2028-2100 matches 430(b) in 73 of 73 years; Trustees path 65 of 65. G2 partial (no issue) |
| References | 30 checked, 30 correct; new anchors #u_3_C, #i, #2, p-273.10(e)(4)(ii) exist |
| Code patterns | No hard-coded legal value; changelog top-level and typed changed (G19 adds a clause); ruff format --check and ruff check pass on the changed Python files |
| Tests and mutation | 38 mutants against T: 35 killed, 1 equivalent, 2 G8 scenario probes (G17). A second set of 15: 14 killed, 1 equivalent. Two $150-tie mutants survive (G15) |
| Probes | Full parameter tree at both heads: 0 values move on 2036-01-01, IRS unchanged, 743 values move from 2037 |
| Branch | 6 ahead / 38 behind main. Merge hold until spm-calculator 1.1.0 |
| Other reviews | None since round 1, except your reply |
Review Severity: APPROVE
No critical or should-address item is open. All 1 critical and 4 should-address items from round 1 are resolved. Only suggestions remain: G2 (partial), and G15 to G19.
Next Steps
The suggestions are optional. The merge waits only for the PR's own hold until spm-calculator 1.1.0 is released.
- Optional, small: add the three-line tie test (G15), change 2.26% to 2.27% (G16) and add the changelog clause (G19).
- Optional: add the YAML guard test (G17) and the refresh note in the two docstrings (G18).
- Open the HHS 9902(2) follow-up issue and put its number in
gov/hhs/uprating.yaml(G2). Open the Trustees 2025 issue for the owner of #8220 (G9 and the wage-indexed amounts). - If you change anything, run
make format, then T andtest_extend_single_year_dataset.py. - Merge only after spm-calculator 1.1.0 is released.
…ees wage base (#10453) Projected federal poverty guidelines grew by CPI-U CY(Y)/CY(Y-1), one year ahead of 42 U.S.C. 9902(2) and the HHS notices, which use CY(Y-1)/CY(Y-2) (#10451). A new gov.hhs.fpg_uprating index holds the prior calendar year's CPI-U at each guideline year: BLS actuals through 2025, then the 2025 actual grown at CBO's February 2026 calendar-year rates. It reproduces the published 2023-2026 four-person increases within 0.12%. gov.hhs.uprating keeps its 2026 hold and now serves only Head Start and Early Head Start spending, so the partner pins do not move. The 2027 Oregon ERDC and California AB 2591 expectations move with the guidelines. The Trustees 2025 scenario re-extended the payroll cap from its NAWI but not the wage-indexed amounts, so its wage base kept CBO's cap from 2036 (#10452). It now reruns that extension. Also from the #10227 review: a 430(b) tie test, a guard that the extensions keep every authored YAML value, refresh notes in two docstrings, the SSA proxy note's 2.27%, and a rename of the mock end-year constant. Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Important
Do not merge yet. This PR is marked ready only so CI runs. Per the merge hold in PolicyEngine/policyengine-api#3926, none of the 2036 PRs merge until spm-calculator 1.1.0 (PolicyEngine/spm-calculator#51) is released. Reviews are welcome now.
Summary
Part of the US 2036 extension, tracked in PolicyEngine/policyengine-api#3926. CBO's February 2026 baseline runs through 2036, and its 10-year window is now 2027–2036. Several upraters still use older CBO vintages and stop in 2034 or 2035, so their 2036 values were extrapolations. This PR loads the February 2026 projections, so every refreshed series is CBO-based through 2036 and extrapolation starts in 2037.
It also extends the payroll cap after 2036 with the 42 U.S.C. 430(b) fixed-base formula, which the previous chained formula did not follow.
Based on
mainafter #10225 merged, and merged withmainagain on 2026-10-23 (no conflicts). It grows from #10225's 2027 COLA and cap actuals and from SSA's published 2025 wage index.How each series is refreshed
Each uprater grows from its latest actual at CBO's projected rate. Pasting CBO's levels after the actuals would understate the first projected year: actual 2026 inflation, and the official 2027 COLA and cap, came in above CBO's February path. With levels, the 2028 COLA would be 1.68% (CBO's 2027Q3 CPI-U 341.281 × 327.075 / 333.952 = 334.253, over the 2026Q3 CPI-W 328.746) against CBO's 2.49%, and the 2028 cap would rise 2.96% against 3.61%.
gov.ssa.upratinggov.usda.snap.upratinggov.hhs.upratinggov.ssa.nawigov.irs.payroll.social_security.capgov.bls.cpi.cpi_wgov.bls.cpi.cpi_u,gov.bls.cpi.c_cpi_ugov.irs.upratingget_irs_cpi; #9105 tracks the one-month offset from the 12 months ending August in 26 U.S.C. 1(f))HHS holds 2026. The 2026 poverty guidelines are explicit values, but Head Start spending is uprated from its 2023 values by this index. Partner contract tests under
partners/analytics_coverage/.../head_startand.../early_head_startpin 2026 per-slot amounts derived from 328.4. Moving 2026 to CBO's February path (331.3) would change about 28 of those expected values by +0.89%. So 2026 keeps 328.4, and 2027–2036 grow from it at CBO's February 2026 rates. Poverty-guideline uprating from 2027 therefore follows CBO's growth exactly, and no partner test changes. The YAML also notes thatgov/hhs/fpg.yamlgrows guideline year Y by CPI-U CY(Y)/CY(Y-1), one year ahead of the CY(Y-1)/CY(Y-2) interval in 42 U.S.C. 9902(2) and the HHS notices. That mapping predates this PR (#5911), and aligning it changes a shared index, so it is left for a separate PR.CPI-U and chained CPI-U keep CBO's 2035 point and add its 2036 point.
extend_parameter_values(..., last_projected_year=2034)overwrote that instant with an extrapolation: 407.40 and 219.08.last_projected_yearis 2036, so extrapolation starts at the 2037 instant. HHS 2036 already uses 416.542, so the model now holds one 2036 CPI-U projection.extend_single_year_datasettakes its default end year from the last authored CPI-U year, so single-year datasets now extend through 2036 by default, not 2035.test_extend_single_year_dataset.pypins that year and moves to 2036.The payroll cap after 2036 follows 42 U.S.C. 430(b). The extension now computes the base for year Y as the larger of the base for Y-1 and $60,600 × NAWI(Y-2) / NAWI(1992), rounded to the nearest $300. The previous chained form, prior cap × NAWI(Y-2) / NAWI(Y-3), follows the wording of 20 CFR 404.1048(b)(2)(i), which Pub. L. 103-296 sec. 321(g)(1)(A) replaced for bases after 1994. On SSA's published series the fixed-base formula reproduces all 30 automatically adjusted bases from 1995 to 2027 (2010, 2011 and 2016 had no COLA, so no adjustment); the chained form reproduces 20. The 2028–2036 caps in the YAML already used 430(b), so this removes a seam at 2037: 2037–2100 now match 430(b) in all 64 years. The Trustees 2025 scenario calls the same function.
The data comes from CBO's February 2026 Economic Projections (quarterly and calendar-year
cpiuandchained_cpiu) and Tax Parameters (tp_ss_max_earnings). I read them from the machine-readable US-CBO/cbo-data at284a956, the same pinned commit spm-calculator uses. cbo.gov returns 403 to scripted downloads, so I checked each series' sheet and row against Wayback captures of the workbooks, and the YAML references cite the files with their sheet and row. Each YAML value has its formula in a comment.Unchanged:
Before and after
Values come from loading each tree's parameters (
system.parameters) after the extensions run: the base ismain(same uprating inputs as 3a5215d), the after is this branch. The 2037, 2050 and 2100 rows are extrapolated in both.Long run. From 2037 each series grows at its last CBO growth rate. NAWI and the cap grow at 258,600 / 250,500 = 3.23% a year (CBO's 2036 and 2035 bases, which CBO rounds to $300), against 3.40% before. By 2100 NAWI is 11.0% lower than on
main(804,774 against 904,606) and the cap 10.8% lower (1,995,300 against 2,235,900); the 2040 PIA bend points are $2,059 and $12,414 against $2,094 and $12,624. CBO's base growth for 2029–2036 ranges from 3.19% to 3.79%, so a multi-year rate would give a somewhat faster long-run path; that is a method change for a follow-up.2036, before and after:
SSA uprating (January), 2027–2037, 2050 and 2100
SNAP uprating (October), 2027–2037, 2050 and 2100
HHS uprating (January), 2027–2037, 2050 and 2100
IRS uprating (January), 2027–2037, 2050 and 2100
NAWI, 2027–2037, 2050 and 2100
Payroll cap, 2027–2037, 2050 and 2100
CPI-U (February instant), 2027–2037, 2050 and 2100
Chained CPI-U (February instant), 2027–2037, 2050 and 2100
CPI-W (August instant), 2027–2037, 2050 and 2100
Tests
tests/policy/baseline/parameters/test_uprating_extensions.py:test_upraters_encode_cbo_february_2026_projections(100 cases) checks every CBO-based value of the SSA, SNAP and HHS upraters, NAWI (through 2034), CPI-W, CPI-U and chained CPI-U against CBO's February 2026 data applied to its anchor, at the YAML's precision. The expected values come only from CBO's data and the named BLS and SSA actuals, never from a parameter. They include the last two CBO points of each series, which set its 2037–2100 growth, so an off-by-one end year or a wrong seam value fails.test_projected_payroll_caps_follow_430b_through_2036checks the 2028–2036 caps against 42 U.S.C. 430(b) and pins 2036 at 260,400.test_irs_uprating_averages_cbo_chained_cpi_u_pointschecks IRS uprating for 2029–2036 against CBO's chained CPI-U points over the August–July window.test_upraters_extrapolate_only_after_cbo_projectionsruns over the eight refreshed series and checks that each holds its final projected growth only after CBO's last year.tests/microsimulation/data/test_extend_single_year_dataset.pynow expects the CPI-U YAML to end in 2036.Run locally on Python 3.11 with policyengine-core 3.33.12:
test_uprating_extensions.py, 141 passed; the ERDC integration, AB 2591 andbasic_standard_deduction.yamlfiles, 42 passed.CI on the full suites found three test files whose expectations move only because of the refreshed projections. c3d0880 and 493ec45 update them:
states/or/delc/erdc/integration.yaml, Case 2: the 2027 ERDC initial income limit for 2 peopleusda/snap/snap_max_allotment.yaml: FY2028 maximum allotment for 4 peoplecontrib/states/ca/ab2591/ca_ab2591.yaml: the reform's 2027 standard deduction (six cases)The ERDC case and the AB 2591 header now show their derivations.
basic_standard_deduction.yaml's 2042 derivation comments now follow the chained CPI-U extension, which starts after the 2036 point (2041: 246.299); its expected values don't move. Every other suite passed at 493ec45, including the Contrib suites and Household API Partners, so the Head Start partner tests don't move. Nopartners/**file is edited.axiom: n/a: projection data refresh, no change in law
🤖 Generated with Claude Code
https://claude.ai/code/session_01LqCGPgxDukji8Bhs57c5rH