Skip to content

v3 household section: US and UK households with SPM geography, calculation provenance and UK input suggestions - #1338

Closed
anth-volk wants to merge 7 commits into
mainfrom
apiv2/1d-1-v3-uk-us-households
Closed

anth-volk wants to merge 7 commits into
mainfrom
apiv2/1d-1-v3-uk-us-households

Conversation

@anth-volk

@anth-volk anth-volk commented Oct 19, 2026 •

Copy link
Copy Markdown
Collaborator

Fixes #1336

What changes

The household section of v3's report (each household the reader describes, run under the report's baseline and reform) already runs UK households in the UK since 15d4b45. This PR finishes US and UK support:

  • The country is required, never read as the US. compareHouseholds took the US result rows (the taxes and benefits it lists) for any country without its own; a country without its own rows is now an error. HouseholdImpactResult no longer defaults its currency to us. The unused simple-input run (FlagshipHouseholdInput, buildHouseholdPayload, runFlagshipHousehold, describeHouseholdInput), which always built a US household with a US state, is removed; its run tests now cover runFlagshipHouseholdPayload.
  • Calculation provenance is kept. The run called fetchHouseholdCalculation, which drops policyengine_bundle, spm_config and spm_provenance. It now calls fetchHouseholdCalculationWithBundle and keeps them per policy (FlagshipHouseholdRun.provenance). A response without a bundle records null.
  • US SPM geography and its footnote. The section no longer passes hideSpmGeography: a US household still starts on national thresholds, and the reader can choose local thresholds by county with a county FIPS code; the household's spm setting and county_fips are sent with it. The SPM methodology footnote shows under the summary and the net income breakdown (from each response's settings and receipt; nothing for a response without one, such as any UK household), and the varying earnings and marginal tax rate views no longer hide their own footnote. SPMMethodologyFootnote now also accepts just a calculation's SPM settings and receipt.
  • UK input suggestions. "Related to this reform" came from a parameter dependency map traced only from policyengine-us, so UK reports suggested nothing. app/scripts/build-parameter-dependency-map.py takes --country uk and traces policyengine-uk over 400 generated households (the UK microdata is not public; which parameters a formula reads depends on which formulas run, not on the households, so the population varies ages, couples, children, pensioners, disability, every region, tenure and council tax band, and each income source). loadParameterDependencies(countryId) loads each country's map once, and every caller names its country: the validation surfaces (scorecard matches, calibration matches, reform readers, scorecard comparisons) ask for the US map by name, and a call without a country loads none. Suggestions are limited to inputs that describe a household, so microdata-only inputs no longer use up the list. For a change to Universal Credit's child element, the suggestions now include a child's age, childcare costs and disability.
  • UK acceptance checks from Bug in UK household calculation [MOVE TO API] #358 and UAT: UK Household (PR #556) #562 (tests only; see below).

Live as soon as it merges. Calculations stay on the Public API's v1 household routes (create the household, then calculate it under each policy). No environment variable, workflow or deployment configuration is added or changed.

Evidence

  • Bug in UK household calculation [MOVE TO API] #358: the issue's household (an adult earning £100, a dependant aged 10 earning £10, one benefit unit, a BRMA, region and local authority that name different places) calculates in policyengine-uk 2.130.1, the version the .py bundle 6.7.5 pins, run locally for 2025 (net income £10,159.73) and 2026. No calculation was sent to production.
  • The UK map: policyengine-uk 2.130.1 with policyengine-core 3.33.0; all 1,163 variables calculate with no failures; 688 parameter paths and 989 consumed variables; 195 KB, loaded lazily by the household section of UK reports only.

Tests

New or changed, all passing:

  • householdRun.test.ts (26): a country without its own result rows throws; each response's bundle and SPM provenance are kept per policy; one calculation for both policies gives the reform the baseline's provenance; a response without a bundle records null; the run mechanics on runFlagshipHouseholdPayload.
  • HouseholdImpactSection.test.tsx (29): the builder stand-in now renders the real SPMGeographyChoice unless hidden. A US household shows the choice on national thresholds; choosing county thresholds and a FIPS code sends both; a response with an SPM receipt shows the methodology under the result, one without shows none; a UK household shows no SPM choice.
  • HouseholdBreakdownsSPM.test.tsx (new, 2): varying earnings and marginal tax rates keep their SPM footnote.
  • HouseholdImpactSuggestions.test.tsx (new, 2): a UK reform to Universal Credit's child element suggests the inputs it reads, never a microdata-only input.
  • parameterDependencies.test.ts (+5) and householdSuggestions.test.ts (+1): each country has its own map; the UK map is traced from policyengine-uk; the US map is the one the validation surfaces ask for; a call without a country loads none (also a type error).
  • UKHouseholdAcceptance.test.tsx (new, 4): Bug in UK household calculation [MOVE TO API] #358's household is sent as described and its result shows; UAT: UK Household (PR #556) #562's couple and child share one benefit unit and one household; an input set on the benefit unit is sent on the benefit unit; the household runs under the report's two policies and reads in pounds. These check existing behavior, so they could not fail first: each was confirmed to fail when the section sent a new household instead of the built one, or ran a UK household against the US API.
  • ReportViewHousehold.test.tsx and HouseholdImpactAnalytics.test.tsx: their mocks follow the new calculation call.

Full app suite (after rebasing onto main with #1334 and #1335): 5,342 passed, 10 skipped, before the review fixes; with them, the suite on the PR above this one, which contains this branch, passes 5,418 with 10 skipped. Two tests in ScorecardComparisons.test.tsx fail locally on this branch and on main alike (currency formatting, "£1B" against "£1.0B"); they are unrelated, and pass in CI. All CI checks pass on this PR. tsc, ESLint and Prettier are clean; the calculator type check and build pass.

Overlaps

🤖 Generated with Claude Code

@anth-volk
anth-volk added this pull request to stack #1340 October 19, 2026 22:12
@anth-volk anth-volk changed the title apiv2/1d 1 v3 uk us households v3 household section: US and UK households with SPM geography, calculation provenance and UK input suggestions Oct 19, 2026
@anth-volk
anth-volk force-pushed the apiv2/1d-1-v3-uk-us-households branch from c702c7a to ee3f6bd Compare October 19, 2026 22:15
anth-volk and others added 5 commits October 20, 2026 02:17
The household section already runs each household in the report's
country, but the result code still fell back to the US:

- compareHouseholds took the US result rows (its taxes and benefits)
  for any country without its own, and defaulted its country to "us".
  The country is now required, and a country without its own result
  rows is an error instead of a US reading.
- HouseholdImpactResult defaulted its currency country to "us"; the
  section always passes it, and it is now required.
- The unused simple-input run (FlagshipHouseholdInput,
  buildHouseholdPayload, runFlagshipHousehold, describeHouseholdInput
  and their helpers) built a US household with a US state whatever the
  report's country. Nothing called it since the section moved to the
  household builder, so it is removed, and its run tests now cover
  runFlagshipHouseholdPayload.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The section's run read only the result of each v1 household
calculation (fetchHouseholdCalculation), so the response's
policyengine_bundle, spm_config and spm_provenance were dropped. It now
calls fetchHouseholdCalculationWithBundle and keeps them per policy on
the run (FlagshipHouseholdRun.provenance), for the SPM methodology
footnote and for Reproduce in Python. A run that calculates once for
both policies gives the reform the baseline's provenance; a response
without a bundle records null rather than a guessed version.

The section's tests, including the analytics tests from #1334, mock
the new call.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The section hid the household builder's Supplemental Poverty Measure
geography choice (hideSpmGeography) and ran every US household on
national thresholds. It now shows the choice: a US household still
starts on national thresholds, and the reader can pick local thresholds
by county, with a county FIPS code. The household's spm setting and
county_fips are sent with it, as in the household builder.

With a real choice, the methodology footnote says something again:

- Under the summary and the net income breakdown, the result shows the
  calculation's SPM settings and receipt (SPMMethodologyFootnote), read
  from each policy's response. One calculation for both policies shows
  once. A response without a receipt (any UK household) shows nothing.
- The earnings variation and marginal tax rate views no longer hide
  their own variation footnote.

SPMMethodologyFootnote now also takes just a calculation's SPM settings
and receipt, so the v3 run's provenance can be shown without a full
household output.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… map

The household section leads its variable search with the inputs a
reform's parameters read, from a dependency map traced from the model.
Only policyengine-us had a map, so UK reports suggested nothing.

- build-parameter-dependency-map.py takes --country. The UK map traces
  policyengine-uk 2.130.1 (the version the .py bundle 6.7.5 pins) over
  400 generated households: the UK microdata is not public, and which
  parameters a formula reads does not depend on the households, only on
  which formulas run, so the population varies ages, couples, children,
  pensioners, disability, every region, tenure and council tax band, and
  each income source. All 1,163 variables calculate; the map has 688
  parameter paths and 989 consumed variables (195 KB).
- loadParameterDependencies(countryId) loads each country's map once;
  without a country it is the US map the validation surfaces read.
- The section loads the report's country's map, and suggests only inputs
  a reader describes a household with, so microdata-only inputs (such as
  a public-spending imputation) no longer use up the suggestion list.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Tests only: the section already sends UK households as built and runs
them in the UK, so these check that behavior against the two issues
rather than drive a change. Each was confirmed to fail when the section
sent a new household instead of the built one, or ran a UK household
against the US API.

- #358: the issue's household (an adult earning £100, a dependant aged
  10 earning £10, one benefit unit, a BRMA, region and local authority
  naming different places) is sent as described and its result shows.
  The v1 API once failed on it; run locally, policyengine-uk 2.130.1
  (the version the .py bundle 6.7.5 pins) calculates it for 2025 and
  2026.
- #562: a couple and a child share one benefit unit and one household;
  an input set on the benefit unit is sent on the benefit unit; the
  household runs under the report's two policies and reads in pounds.
  Saving and reusing a household, #562's second item, belongs to the
  standalone household report.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@vercel

vercel Bot commented Oct 19, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
policyengine-calculator-next Ready Ready Preview Oct 20, 2026 1:10pm UTC
policyengine-website Ready Ready Preview Oct 20, 2026 1:10pm UTC

Request Review

anth-volk and others added 2 commits October 20, 2026 17:05
Comments and test names added for v3 households called the Public API
"the v1 API", and called the taxes and benefits a result lists its
"lines". They now say "the Public API" and "rows"; the fixture
COUNTRY_WITHOUT_HOUSEHOLD_LINES is now COUNTRY_WITHOUT_HOUSEHOLD_RESULT_ROWS.

Wording and naming only, so no test could fail first. The affected
tests (householdRun.test.ts, UKHouseholdAcceptance.test.tsx) pass.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
loadParameterDependencies still defaulted to the US map when called
without a country, the implicit US default this PR removes elsewhere.
The country is now required: the four validation callers (scorecard
matches, calibration matches, reform readers and scorecard comparisons)
ask for the US map by name. Their comments no longer say the dependency
map is US-only, as a UK map now exists; they say the validation data is
the US model's, so only the US map is read.

Test first: parameterDependencies.test.ts asks for a map without a
country and expects a rejection, with a @ts-expect-error. Before the
change the call resolved the US map, and tsc reported the directive as
unused; both now pass.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

This branch was successfully deployed

2 active deployments
Preview – policyengine-calculator-next — aee67665 Deployed Oct 20, 2026 by vercel[bot]
Preview – policyengine-website — aee67665 Deployed Oct 20, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

v3 report household section: US and UK households with SPM geography, calculation provenance and UK input suggestions

1 participant