Repository navigation
Add household_options.time_period to the country metadata - #4159
Merged
Merged
Conversation
The app reads one year list, economy_options.time_period, for household and society-wide year menus alike. Add a separate household list so the two can differ later. economy_options is unchanged. - US: the years the bundle's certified SPM forecast covers, up to the last year in the CPI-U parameter's source file, newest first like the US society-wide years. The forecast is the one the SPM metadata already loads, so the Public API loads no extra dataset at startup. Without a certified forecast the US household years are the society-wide years. - UK: the rule for the UK society-wide years (uk_economy_years). - Any other country: its society-wide years. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #4159 +/- ##
==========================================
- Coverage 88.22% 88.21% -0.01%
==========================================
Files 285 286 +1
Lines 16847 16893 +46
Branches 2741 2754 +13
==========================================
+ Hits 14863 14903 +40
- Misses 1302 1304 +2
- Partials 682 686 +4 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
anth-volk
marked this pull request as ready for review
November 3, 2026 20:37
anth-volk
added a commit
to PolicyEngine/policyengine-app-v2
that referenced
this pull request
Nov 3, 2026
Household readers no longer use economy_options.time_period when the metadata has no household list. This PR merges only after the Public API change that adds household_options (PolicyEngine/policyengine-api#4159) is in production. - household_options is required in the metadata response type, and householdOptions in the metadata state. The reducer starts it, and resets it, as { time_period: [] }, the way it does economyOptions. - getHouseholdYearOptions and getHouseholdDateRange read householdOptions.time_period only. With an empty list, the date range is still 2022 to 2035, as before the metadata loads. - The tests of the removed fallback are gone. Every mocked metadata response and state now includes household_options, with the same years as its economy_options unless the test is about household years. - The PolicyCreationModal test replaces the mocked state object instead of changing it in place, since the memoized selectors keep their result for as long as they get the same state object. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This was referenced Nov 3, 2026
Open
This branch was previously deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #4160
Summary
Adds a separate household year list,
household_options.time_period, to the/{country}/metadataresponse. Its items have the same shape aseconomy_options.time_perioditems:{"name": <int year>, "label": "<year>"}.Today the app reads
economy_options.time_periodfor every year menu: household reports, society-wide reports and the policy editors. This is the first step towards offering US household calculations for 2022 and 2023 while no longer offering society-wide US runs for those years, whose data is nearly empty. A later PR will narrow the USeconomy_options.time_periodto start at 2024. This PR leaveseconomy_optionsunchanged (build_microsimulation_optionsis identical tomaster).Where each country's household years come from
policyengine_api/household_years.py,us_household_years): the years covered by the bundle's certified SPM forecast (policyengine_api/spm.py, newcertified_spm_forecast_years, which readsforecast.yearsfrom the forecast the bundle pins byforecast_content_sha256), keeping only the years up to the last year written in the CPI-U parameter's source file (CPI_U_PARAM_PATH,gov.bls.cpi.cpi_u, read with policyengine-us'sget_parameter_last_year). The US model answers an SPM calculation in any year outside the forecast withSPM_YEAR_UNAVAILABLE. The list is newest first, like the US society-wide years.spmmetadata already reportsavailable: false), the US household years fall back to the US society-wide years, and a warning is logged. Startup does not fail in that case, as it does not today.uk_economy_yearsinpolicyengine_api/economy_years.py, oldest first likeeconomy_options.time_period.economy_options.time_period(an empty list if it has none). The Public API serves onlyusanduktoday (SupportedCountryId), so this applies to no served country.Values with the locked dependencies (
policyengine[models]==6.12.0)economy_options.time_period.Startup time
No dataset is loaded and no simulation is run. The SPM forecast is the one
spm_metadataalready loads at import, and it is cached, so it is still read once per process (_selected_forecast.cache_info()after import: 1 miss, 2 hits). Building the US list takes about 28 ms per country model load, mostly reading the CPI-U YAML file; the UK list takes under 1 ms.Not changed
economy_optionsfor every country.tests/contract/registry.py) and generated migration documents, which list the/{country}/metadatafields that the v2 migration checks. They don't listhousehold_options.Testing
Only the new tests were run, each selected by node ID; all 14 pass:
tests/unit/test_spm_settings.py::test_certified_forecast_years_are_the_artifacts_yearstests/unit/test_spm_settings.py::test_certified_forecast_years_are_none_without_a_certified_forecast([False],[True])tests/unit/test_spm_settings.py::test_certified_forecast_years_are_none_when_the_forecast_cannot_loadtests/unit/test_household_options.py::test_us_household_years_stop_at_the_last_cpi_u_year_newest_firsttests/unit/test_household_options.py::test_us_household_years_are_the_society_wide_years_without_a_forecasttests/unit/test_household_options.py::test_a_country_without_household_rules_offers_its_society_wide_yearstests/unit/test_household_options.py::test_us_household_years_are_the_certified_forecast_years_to_cpi_utests/unit/test_household_options.py::test_us_household_years_include_2022_and_2023tests/unit/test_household_options.py::test_uk_household_years_follow_the_uk_society_wide_ruletests/unit/test_household_options.py::test_household_years_have_the_shape_of_society_wide_years([uk],[us])tests/unit/test_household_options.py::test_us_society_wide_years_are_unchangedtests/unit/test_household_options.py::test_uk_society_wide_years_are_unchangedAlso run:
ruff formatandruff checkon the changed files (no changes, no findings),python scripts/run_quality_guards.py(all guards pass;spm.pyis now 790 lines, under the 800-line limit), andBASE_SHA=origin/master bash .github/scripts/check_changelog_fragment.sh(passes). The values above were read by calling the Flask/{country}/metadataroute with a test client.Changelog fragment:
changelog.d/household-time-period.added.md.🤖 Generated with Claude Code