Repository navigation
Clarify Boolean masks and gross wealth tax metadata - #2582
Conversation
Aggregate impact on certified data: passBase Checks: 0 broken by this change, 1 failing on both sides, 0 fixed. Moves flagged for review: 0 (thresholds in Notes
Moves flagged for reviewNone. Spending by benefit and service
Caseloads
Household net income by decileNo household's net income changes in any year. No change in any year: receipts by tax head; government balance, each component counted once; model totals; household income totals; population; poverty rates; people in poverty; inequality; mean household net income in each side's own deciles; standard reform costings (change in gov_balance); standard reforms: change in each reform's target. Checks failing on both base and head (1)
Counted-once checkEach of 84 components was raised by £1 per unit in 2026-27, and every head of its totals was read household by household: its own head must rise by exactly £1, no other tax head may move, no other benefit may rise, and the model's own total must move by what its heads moved. A head that breaks a rule is measured again twice: with every other head held at its baseline value, and with every other head held at its value after the first £1 while the component rises again. It fails where either still shows the response. 0 failed; 0 were skipped. Provenance
Dataset: Receipts by tax head: head levels
Spending by benefit and service: head levels
Caseloads: head levels
Government balance, each component counted once: head levels
Model totals: head levels
Household income totals: head levels
Population: head levels
Poverty rates: head levels
People in poverty: head levels
Inequality: head levels
Mean household net income in each side's own deciles: head levels
Standard reform costings (change in gov_balance): head levels
Standard reforms: change in each reform's target: head levels
|
vahid-ahmadi
left a comment
There was a problem hiding this comment.
@juaristi22 thanks, first-round review at fbb6354. No must or should findings; approving with two nits.
What I checked
- Boolean masks:
age,is_SP_ageandis_uc_claimantcomparisons are allbool(is_SP_age.py:5,is_uc_claimant.py:17), so*and&give the same arrays. On the certified data (enhanced_frs_2024_25.h5, policyengine-uk-data 1.58.1, sha256 checked),bi_maximum,household_uc_unreported_claimantsandnon_primary_residence_wealth_taxhash identically on this PR and on main for 2025 and 2027. (The main side was run in a checkout of main's versions of these files.) Caveat: the basic-income amounts and wealth tax rate are zero at baseline, so for those two the YAML reform tests below are the stronger evidence. - Tests: basic income and disability basic income YAML plus
uc_assessable_capital.yaml, 25 passed;test_household_benefits_properties.pyandtest_warning_filters.py, 35 passed. CI at head all green. - Metadata:
non_primary_residence_wealth_taxtaxesmax_(0, total_wealth - main_residence_value), andtotal_wealthadds property, corporate and private pension wealth and savings with no debt (net_wealth.pyis the netted version). So "gross … without deducting mortgage or other debt" is accurate, and the old variable documentation ("net wealth") was wrong, as #2560 says. Formula untouched.
Findings
-
nit:
policyengine_uk/parameters/gov/contrib/cec/non_primary_residence_wealth_tax.yaml:17-18andnon_primary_residence_wealth_tax.py:6-9. "Gross household wealth" reads as all assets, buttotal_wealthhas no physical wealth (vehicles, contents) and no current defined benefit pension rights. Naming the base, for example "grosstotal_wealth(property, corporate and private pension wealth and savings) less the main residence value", would be exact. The old parameter description listed components; the new one drops them. -
nit: the formula floors the base at zero (
max_(0, …)); one clause saying so indocumentationwould complete it. Optional.
Overlap and merge order: no file overlap with #2583 (wealth deciles) or any other open PR I found; both are mergeable, so either order works. #136 and #2560 stay open, as the body says.
🤖 Generated with Claude Code
|
Merged by the UK hub (Claude session 8e19f9d5) at head
|
Refs #136, #2560
Use Boolean conjunctions for the child/adult basic-income eligibility masks and the unreported Universal Credit claimant mask. All operands are Boolean, so amounts and claimant counts keep their existing behavior.
Describe the non-primary-residence wealth tax as a tax on gross household wealth excluding the main residence, with no debt deducted. The tax formula stays the same. Both issues remain open for their broader work: this PR covers the named Boolean sites and factual metadata only, leaving the debt-allocation design in #2560 unresolved.
Validation: 41 existing focused tests pass (16 YAML cases and 25 Python tests), with no failures or skips. They cover basic-income age/rate and final-payment cases, UC capital/claimant allocation, the existing conservation property and parameter descriptions.
make formatpasses across all 1,943 Python files; no formatter changes. Tests used the existing Python 3.13.14/Core 3.33.2 environment throughuv run --offline --active --no-sync, with exact checkout imports and no dependency installation. Full-suite, population and documentation-build validation were not run locally for this behavior-preserving refactor and metadata clarification; the combined PR shares one normal initial CI cycle.axiom: n/a: Boolean-only refactor and documentation of the existing gross wealth base; no legal rule, rate or tax formula changes.
Independent local code and documentation review is complete with no open findings at
fbb635461fb8b38d6ca43d9501822c6646dcf30e.