Repository navigation
Count other investment income in capital income, and test it in every income measure - #2746
Conversation
Income tax charges other_investment_income as savings income (taxable_savings_interest_income), but market_income, household_market_income and hbai_household_net_income left it out, so household net income carried the tax without the income. Add it to all three lists, with a YAML test that pins it against the same amount of bank interest. Fixes #2733. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The HBAI validation page's investment income row now names other_investment_income, which hbai_household_net_income counts since the previous commit (Max's review of #2736, point 4). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… income measure
capital_income ("Income from savings or dividends") added bank interest,
ISA interest and dividends but not other_investment_income, the National
Savings, gilt and other securities interest that income tax charges as
savings income. It now adds it next to savings_interest_income, as market
and HBAI income do. No formula reads capital_income, so tax, benefits and
the other income measures are unchanged. The legacy ISA contract case that
sets other investment income now expects it in capital income.
The YAML cases also check capital, gross and household net income, where
the market income gap showed. A property test simulates each case with
no interest, with bank interest and with the same amount as other
investment income: tax and every household income measure treat the two
alike, market and capital income rise by the interest, and net and HBAI
income rise by the interest less its tax.
Fixes #2745.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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
Standard reform costings (change in gov_balance)
Standard reforms: change in each reform's target
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. Checks failing on both base and head (1)
Counted-once checkEach of 91 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
|
|
Review of 9ec12db (this PR's own commit). #2736 merged at 11:05 today as a merge commit, so No musts, no shoulds. Three nits.
Checked, no issue
What I ran (fresh shallow clone at 9ec12db, fresh
Not checked: the full test suite (CI covers it), ruff, the other pe-uk-data datasets beyond CI at 9ec12db: all 20 checks pass, including Test / YAML, Python 1-6 and Aggregate impact. Mergeable, state CLEAN. Verdict: ready to approve. #2736 has landed and CI is green, so nothing blocks it. The nits are wording only and don't need to hold it. 🤖 Generated with Claude Code |
The test came from #2746 after this branch's CI ran. Its default band D household in England now gets the £100 payment in 2026, so gross, net and HBAI income each rise by 100. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Fixes #2745
This follows #2736, which is in the merge queue. The branch is built on #2736's head (22ae4d3), so the diff shows #2736's two commits too until it lands. After that, only this PR's commit (9ec12db) remains.
What and why
capital_incomeis "Income from savings or dividends". It adds bank interest, ISA interest and dividends, but it left outother_investment_income: interest on National Savings products, gilts and other securities, and from trusts. Income tax charges that column as savings income.capital_incomenow adds it next tosavings_interest_income, as Count other investment income in market and HBAI income #2736 does for market and HBAI income.capital_income. So income tax, benefits, household net income, HBAI income and every costing are unchanged. Only thecapital_incomeoutput moves, and only on datasets that carry the column; the enhanced FRS doesn't.test_unmarked_legacy_conversion_preserves_cash_and_supplied_exemptions[signed-and-T-differs-from-I]sets £500 of other investment income. It expected capital income to equal the legacy gross interest alone. It now expects the gross interest plus the £500.Tests
other_investment_income_in_household_income.yaml: both cases now also checkcapital_income,household_gross_incomeandhousehold_net_income.test_other_investment_income_household_income_properties.py: Hypothesis, 25 examples plus one pinned example, about 10 seconds locally.capital_income@2026: [0.] differs from 2000.0) and the property test fails atcapital_income. Both pass here.uv run --frozen:policyengine-core teston the YAML above,gov/hmrc/isa/isa_income.yamlandgov/hmrc/income_tax/charges/winter_fuel_payment_charge.yaml, the other files that checkcapital_income: 50 passed.pyteston the property test,test_isa_income_contract.pyandtest_isa_accounting.py: 66 passed.ruff format --check .andruff check ., with the locked ruff 0.17.2: clean.Reproducer: policyengine_uk/tests/test_other_investment_income_household_income_properties.py::test_other_investment_income_counts_like_bank_interest;
policyengine_uk/tests/policy/baseline/household/income/other_investment_income_in_household_income.yaml::Other investment income counts in market, capital, net and HBAI incomeaxiom: n/a: capital_income is a statistical income measure with no legal provision to encode, and no tax or benefit rule changes
🤖 Generated with Claude Code